mirror of
https://github.com/Instadapp/fluid-contracts-public.git
synced 2024-07-29 21:57:37 +00:00
d7a58e88ff
ARB: deploy protocols
324 lines
591 KiB
JSON
324 lines
591 KiB
JSON
{
|
||
"language": "Solidity",
|
||
"sources": {
|
||
"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n"
|
||
},
|
||
"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.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 AddressUpgradeable {\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 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-upgradeable/utils/ContextUpgradeable.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/interfaces/draft-IERC1822.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n"
|
||
},
|
||
"@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-user’s” 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-user’s” 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 Vault’s 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 Vault’s 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/proxy/beacon/IBeacon.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n *\n * @custom:oz-upgrades-unsafe-allow delegatecall\n */\nabstract contract ERC1967Upgrade {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\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 */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Emitted when the beacon is upgraded.\n */\n event BeaconUpgraded(address indexed beacon);\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(\n address newBeacon,\n bytes memory data,\n bool forceCall\n ) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an\n * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.\n *\n * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\n * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\n * `UUPSUpgradeable` with a custom implementation of upgrades.\n *\n * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.\n *\n * _Available since v4.1._\n */\nabstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment\n address private immutable __self = address(this);\n\n /**\n * @dev Check that the execution is being performed through a delegatecall call and that the execution context is\n * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case\n * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a\n * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to\n * fail.\n */\n modifier onlyProxy() {\n require(address(this) != __self, \"Function must be called through delegatecall\");\n require(_getImplementation() == __self, \"Function must be called through active proxy\");\n _;\n }\n\n /**\n * @dev Check that the execution is not being performed through a delegate call. This allows a function to be\n * callable on the implementing contract but not through proxies.\n */\n modifier notDelegated() {\n require(address(this) == __self, \"UUPSUpgradeable: must not be called through delegatecall\");\n _;\n }\n\n /**\n * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the\n * implementation. It is used to validate the implementation's compatibility when performing an upgrade.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.\n */\n function proxiableUUID() external view virtual override notDelegated returns (bytes32) {\n return _IMPLEMENTATION_SLOT;\n }\n\n /**\n * @dev Upgrade the implementation of the proxy to `newImplementation`.\n *\n * Calls {_authorizeUpgrade}.\n *\n * Emits an {Upgraded} event.\n */\n function upgradeTo(address newImplementation) external virtual onlyProxy {\n _authorizeUpgrade(newImplementation);\n _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);\n }\n\n /**\n * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call\n * encoded in `data`.\n *\n * Calls {_authorizeUpgrade}.\n *\n * Emits an {Upgraded} event.\n */\n function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {\n _authorizeUpgrade(newImplementation);\n _upgradeToAndCallUUPS(newImplementation, data, true);\n }\n\n /**\n * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n * {upgradeTo} and {upgradeToAndCall}.\n *\n * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.\n *\n * ```solidity\n * function _authorizeUpgrade(address) internal override onlyOwner {}\n * ```\n */\n function _authorizeUpgrade(address newImplementation) internal virtual;\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/token/ERC20/ERC20.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/cryptography/EIP712.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation 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 *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private constant _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n /**\n * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\n * However, to ensure consistency with the upgradeable transpiler, we will continue\n * to reserve a slot.\n * @custom:oz-renamed-from _PERMIT_TYPEHASH\n */\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\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 ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\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/Context.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/Counters.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV // Deprecated in v4.8\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/cryptography/EIP712.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/math/Math.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/math/SafeCast.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.2._\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v2.5._\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.2._\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v2.5._\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v2.5._\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v2.5._\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v2.5._\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n *\n * _Available since v3.0._\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.7._\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.7._\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n *\n * _Available since v3.0._\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/StorageSlot.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/Strings.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n"
|
||
},
|
||
"@openzeppelin/contracts/utils/structs/EnumerableSet.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n"
|
||
},
|
||
"contracts/infiniteProxy/interfaces/iProxy.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IProxy {\n function setAdmin(address newAdmin_) external;\n\n function setDummyImplementation(address newDummyImplementation_) external;\n\n function addImplementation(address implementation_, bytes4[] calldata sigs_) external;\n\n function removeImplementation(address implementation_) external;\n\n function getAdmin() external view returns (address);\n\n function getDummyImplementation() external view returns (address);\n\n function getImplementationSigs(address impl_) external view returns (bytes4[] memory);\n\n function getSigsImplementation(bytes4 sig_) external view returns (address);\n\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n}\n"
|
||
},
|
||
"contracts/libraries/bigMathMinified.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.\n/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision\n/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can\n/// result in significant gas cost reduction due to storage space reduction.\n/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.\n/// @dev roundUp is more like a increase 1, which happens everytime for the same number.\n/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.\nlibrary BigMathMinified {\n /// @dev constants to use for `roundUp` input param to increase readability\n bool internal constant ROUND_DOWN = false;\n bool internal constant ROUND_UP = true;\n\n /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).\n /// e.g.:\n /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]\n /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)\n /// => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000\n /// ^-------------------- 51(exponent) -------------- ^\n /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011 (2236301563)\n /// exponent = 0011,0011 (51)\n /// bigNumber = 1000,0101,0100,1011,0100,0000,1111,1011,0011,0011 (572493200179)\n ///\n /// @param normal number which needs to be converted into Big Number\n /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))\n /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))\n /// @param roundUp signals if result should be rounded down or up\n /// @return bigNumber converted bigNumber (coefficient << exponent)\n function toBigNumber(\n uint256 normal,\n uint256 coefficientSize,\n uint256 exponentSize,\n bool roundUp\n ) internal pure returns (uint256 bigNumber) {\n assembly {\n let lastBit_\n let number_ := normal\n if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit_ := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit_ := add(lastBit_, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit_ := add(lastBit_, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit_ := add(lastBit_, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit_ := add(lastBit_, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit_ := add(lastBit_, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit_ := add(lastBit_, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit_ := add(lastBit_, 1)\n }\n if gt(number_, 0) {\n lastBit_ := add(lastBit_, 1)\n }\n if lt(lastBit_, coefficientSize) {\n // for throw exception\n lastBit_ := coefficientSize\n }\n let exponent := sub(lastBit_, coefficientSize)\n let coefficient := shr(exponent, normal)\n if and(roundUp, gt(exponent, 0)) {\n // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number\n coefficient := add(coefficient, 1)\n if eq(shl(coefficientSize, 1), coefficient) {\n // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits\n // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.\n coefficient := shl(sub(coefficientSize, 1), 1)\n exponent := add(exponent, 1)\n }\n }\n if iszero(lt(exponent, shl(exponentSize, 1))) {\n // if exponent is >= exponentSize, the normal number is too big to fit within\n // BigNumber with too small sizes for coefficient and exponent\n revert(0, 0)\n }\n bigNumber := shl(exponentSize, coefficient)\n bigNumber := add(bigNumber, exponent)\n }\n }\n\n /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`\n function fromBigNumber(\n uint256 bigNumber,\n uint256 exponentSize,\n uint256 exponentMask\n ) internal pure returns (uint256 normal) {\n assembly {\n let coefficient := shr(exponentSize, bigNumber)\n let exponent := and(bigNumber, exponentMask)\n normal := shl(exponent, coefficient)\n }\n }\n\n /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).\n /// e.g.\n /// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111\n /// lastBit = ^--------------------------------- 83 ----------------------------------------^\n function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {\n assembly {\n let number_ := normal\n if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit := add(lastBit, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit := add(lastBit, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit := add(lastBit, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit := add(lastBit, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit := add(lastBit, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit := add(lastBit, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit := add(lastBit, 1)\n }\n if gt(number_, 0) {\n lastBit := add(lastBit, 1)\n }\n }\n }\n}\n"
|
||
},
|
||
"contracts/libraries/errorTypes.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary LibsErrorTypes {\n /***********************************|\n | LiquidityCalcs | \n |__________________________________*/\n\n /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)\n uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;\n\n /// @notice thrown when rate data is set to a version that is not implemented\n uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;\n\n /***********************************|\n | SafeTransfer | \n |__________________________________*/\n\n /// @notice thrown when safe transfer from for an ERC20 fails\n uint256 internal constant SafeTransfer__TransferFromFailed = 71001;\n\n /// @notice thrown when safe transfer for an ERC20 fails\n uint256 internal constant SafeTransfer__TransferFailed = 71002;\n}\n"
|
||
},
|
||
"contracts/libraries/liquidityCalcs.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { LibsErrorTypes as ErrorTypes } from \"./errorTypes.sol\";\nimport { LiquiditySlotsLink } from \"./liquiditySlotsLink.sol\";\nimport { BigMathMinified } from \"./bigMathMinified.sol\";\n\n/// @notice implements calculation methods used for Fluid liquidity such as updated exchange prices,\n/// borrow rate, withdrawal / borrow limits, revenue amount.\nlibrary LiquidityCalcs {\n error FluidLiquidityCalcsError(uint256 errorId_);\n\n /// @notice emitted if the calculated borrow rate surpassed max borrow rate (16 bits) and was capped at maximum value 65535\n event BorrowRateMaxCap();\n\n /// @dev constants as from Liquidity variables.sol\n uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n /// @dev Ignoring leap years\n uint256 internal constant SECONDS_PER_YEAR = 365 days;\n // constants used for BigMath conversion from and to storage\n uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\n uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;\n\n uint256 internal constant FOUR_DECIMALS = 1e4;\n uint256 internal constant TWELVE_DECIMALS = 1e12;\n uint256 internal constant X14 = 0x3fff;\n uint256 internal constant X15 = 0x7fff;\n uint256 internal constant X16 = 0xffff;\n uint256 internal constant X18 = 0x3ffff;\n uint256 internal constant X24 = 0xffffff;\n uint256 internal constant X33 = 0x1ffffffff;\n uint256 internal constant X64 = 0xffffffffffffffff;\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC EXCHANGE PRICES /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev calculates interest (exchange prices) for a token given its' exchangePricesAndConfig from storage.\n /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n /// @return supplyExchangePrice_ updated supplyExchangePrice\n /// @return borrowExchangePrice_ updated borrowExchangePrice\n function calcExchangePrices(\n uint256 exchangePricesAndConfig_\n ) internal view returns (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) {\n // Extracting exchange prices\n supplyExchangePrice_ =\n (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) &\n X64;\n borrowExchangePrice_ =\n (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) &\n X64;\n\n if (supplyExchangePrice_ == 0 || borrowExchangePrice_ == 0) {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__ExchangePriceZero);\n }\n\n uint256 temp_ = exchangePricesAndConfig_ & X16; // temp_ = borrowRate\n\n unchecked {\n // last timestamp can not be > current timestamp\n uint256 secondsSinceLastUpdate_ = block.timestamp -\n ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33);\n\n uint256 borrowRatio_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO) &\n X15;\n if (secondsSinceLastUpdate_ == 0 || temp_ == 0 || borrowRatio_ == 1) {\n // if no time passed, borrow rate is 0, or no raw borrowings: no exchange price update needed\n // (if borrowRatio_ == 1 means there is only borrowInterestFree, as first bit is 1 and rest is 0)\n return (supplyExchangePrice_, borrowExchangePrice_);\n }\n\n // calculate new borrow exchange price.\n // formula borrowExchangePriceIncrease: previous price * borrow rate * secondsSinceLastUpdate_.\n // nominator is max uint112 (uint64 * uint16 * uint32). Divisor can not be 0.\n borrowExchangePrice_ +=\n (borrowExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n (SECONDS_PER_YEAR * FOUR_DECIMALS);\n\n // FOR SUPPLY EXCHANGE PRICE:\n // all yield paid by borrowers (in mode with interest) goes to suppliers in mode with interest.\n // formula: previous price * supply rate * secondsSinceLastUpdate_.\n // where supply rate = (borrow rate - revenueFee%) * ratioSupplyYield. And\n // ratioSupplyYield = utilization * supplyRatio * borrowRatio\n //\n // Example:\n // supplyRawInterest is 80, supplyInterestFree is 20. totalSupply is 100. BorrowedRawInterest is 50.\n // BorrowInterestFree is 10. TotalBorrow is 60. borrow rate 40%, revenueFee 10%.\n // yield is 10 (so half a year must have passed).\n // supplyRawInterest must become worth 89. totalSupply must become 109. BorrowedRawInterest must become 60.\n // borrowInterestFree must still be 10. supplyInterestFree still 20. totalBorrow 70.\n // supplyExchangePrice would have to go from 1 to 1,125 (+ 0.125). borrowExchangePrice from 1 to 1,2 (+0.2).\n // utilization is 60%. supplyRatio = 20 / 80 = 25% (only 80% of lenders receiving yield).\n // borrowRatio = 10 / 50 = 20% (only 83,333% of borrowers paying yield):\n // x of borrowers paying yield = 100% - (20 / (100 + 20)) = 100% - 16.6666666% = 83,333%.\n // ratioSupplyYield = 60% * 83,33333% * (100% + 20%) = 62,5%\n // supplyRate = (40% * (100% - 10%)) * = 36% * 62,5% = 22.5%\n // increase in supplyExchangePrice, assuming 100 as previous price.\n // 100 * 22,5% * 1/2 (half a year) = 0,1125.\n // cross-check supplyRawInterest worth = 80 * 1.1125 = 89. totalSupply worth = 89 + 20.\n\n // -------------- 1. calculate ratioSupplyYield --------------------------------\n // step1: utilization * supplyRatio (or actually part of lenders receiving yield)\n\n // temp_ => supplyRatio (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n // if first bit 0 then ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n // else ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n temp_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) & X15;\n\n if (temp_ == 1) {\n // if no raw supply: no exchange price update needed\n // (if supplyRatio_ == 1 means there is only supplyInterestFree, as first bit is 1 and rest is 0)\n return (supplyExchangePrice_, borrowExchangePrice_);\n }\n\n // ratioSupplyYield precision is 1e27 as 100% for increased precision when supplyInterestFree > supplyWithInterest\n if (temp_ & 1 == 1) {\n // ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n temp_ = temp_ >> 1;\n\n // Note: case where temp_ == 0 (only supplyInterestFree, no yield) already covered by early return\n // in the if statement a little above.\n\n // based on above example but supplyRawInterest is 20, supplyInterestFree is 80. no fee.\n // supplyRawInterest must become worth 30. totalSupply must become 110.\n // supplyExchangePrice would have to go from 1 to 1,5. borrowExchangePrice from 1 to 1,2.\n // so ratioSupplyYield must come out as 2.5 (250%).\n // supplyRatio would be (20 * 10_000 / 80) = 2500. but must be inverted.\n temp_ = (1e27 * FOUR_DECIMALS) / temp_; // e.g. 1e31 / 2500 = 4e27. (* 1e27 for precision)\n // e.g. 5_000 * (1e27 + 4e27) / 1e27 = 25_000 (=250%).\n temp_ =\n // utilization * (100% + 100% / supplyRatio)\n (((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) *\n (1e27 + temp_)) / // extract utilization (max 16_383 so there is no way this can overflow).\n (FOUR_DECIMALS);\n // max possible value of temp_ here is 16383 * (1e27 + 1e31) / 1e4 = ~1.64e31\n } else {\n // ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n temp_ = temp_ >> 1;\n // if temp_ == 0 then only supplyWithInterest => full yield. temp_ is already 0\n\n // e.g. 5_000 * 10_000 + (20 * 10_000 / 80) / 10_000 = 5000 * 12500 / 10000 = 6250 (=62.5%).\n temp_ =\n // 1e27 * utilization * (100% + supplyRatio) / 100%\n (1e27 *\n ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) * // extract utilization (max 16_383 so there is no way this can overflow).\n (FOUR_DECIMALS + temp_)) /\n (FOUR_DECIMALS * FOUR_DECIMALS);\n // max possible temp_ value: 1e27 * 16383 * 2e4 / 1e8 = 3.2766e27\n }\n // from here temp_ => ratioSupplyYield (utilization * supplyRatio part) scaled by 1e27. max possible value ~1.64e31\n\n // step2 of ratioSupplyYield: add borrowRatio (only x% of borrowers paying yield)\n if (borrowRatio_ & 1 == 1) {\n // ratio is borrowWithInterest / borrowInterestFree (borrowInterestFree is bigger)\n borrowRatio_ = borrowRatio_ >> 1;\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n\n // Note: case where borrowRatio_ == 0 (only borrowInterestFree, no yield) already covered\n // at the beginning of the method by early return if `borrowRatio_ == 1`.\n\n // based on above example but borrowRawInterest is 10, borrowInterestFree is 50. no fee. borrowRatio = 20%.\n // so only 16.66% of borrowers are paying yield. so the 100% - part of the formula is not needed.\n // x of borrowers paying yield = (borrowRatio / (100 + borrowRatio)) = 16.6666666%\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n borrowRatio_ = (borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_);\n // max value here for borrowRatio_ is (1e31 / (1e4 + 1e4))= 5e26 (= 50% of borrowers paying yield).\n } else {\n // ratio is borrowInterestFree / borrowWithInterest (borrowWithInterest is bigger)\n borrowRatio_ = borrowRatio_ >> 1;\n\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n // x of borrowers paying yield = 100% - (borrowRatio / (100 + borrowRatio)) = 100% - 16.6666666% = 83,333%.\n borrowRatio_ = (1e27 - ((borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_)));\n // borrowRatio can never be > 100%. so max subtraction can be 100% - 100% / 200%.\n // or if borrowRatio_ is 0 -> 100% - 0. or if borrowRatio_ is 1 -> 100% - 1 / 101.\n // max value here for borrowRatio_ is 1e27 - 0 = 1e27 (= 100% of borrowers paying yield).\n }\n\n // temp_ => ratioSupplyYield. scaled down from 1e25 = 1% each to normal percent precision 1e2 = 1%.\n // max nominator value is ~1.64e31 * 1e27 = 1.64e58. max result = 1.64e8\n temp_ = (FOUR_DECIMALS * temp_ * borrowRatio_) / 1e54;\n\n // 2. calculate supply rate\n // temp_ => supply rate (borrow rate - revenueFee%) * ratioSupplyYield.\n // division part is done in next step to increase precision. (divided by 2x FOUR_DECIMALS, fee + borrowRate)\n // Note that all calculation divisions for supplyExchangePrice are rounded down.\n // Note supply rate can be bigger than the borrowRate, e.g. if there are only few lenders with interest\n // but more suppliers not earning interest.\n temp_ = ((exchangePricesAndConfig_ & X16) * // borrow rate\n temp_ * // ratioSupplyYield\n (FOUR_DECIMALS - ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14))); // revenueFee\n // fee can not be > 100%. max possible = 65535 * ~1.64e8 * 1e4 =~1.074774e17.\n\n // 3. calculate increase in supply exchange price\n supplyExchangePrice_ += ((supplyExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n (SECONDS_PER_YEAR * FOUR_DECIMALS * FOUR_DECIMALS * FOUR_DECIMALS));\n // max possible nominator = max uint 64 * 1.074774e17 * max uint32 = ~8.52e45. Denominator can not be 0.\n }\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC REVENUE /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev gets the `revenueAmount_` for a token given its' totalAmounts and exchangePricesAndConfig from storage\n /// and the current balance of the Fluid liquidity contract for the token.\n /// @param totalAmounts_ total amounts packed uint256 read from storage\n /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n /// @param liquidityTokenBalance_ current balance of Liquidity contract (IERC20(token_).balanceOf(address(this)))\n /// @return revenueAmount_ collectable revenue amount\n function calcRevenue(\n uint256 totalAmounts_,\n uint256 exchangePricesAndConfig_,\n uint256 liquidityTokenBalance_\n ) internal view returns (uint256 revenueAmount_) {\n // @dev no need to super-optimize this method as it is only used by admin\n\n // calculate the new exchange prices based on earned interest\n (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) = calcExchangePrices(exchangePricesAndConfig_);\n\n // total supply = interest free + with interest converted from raw\n uint256 totalSupply_ = getTotalSupply(totalAmounts_, supplyExchangePrice_);\n\n if (totalSupply_ > 0) {\n // available revenue: balanceOf(token) + totalBorrowings - totalLendings.\n revenueAmount_ = liquidityTokenBalance_ + getTotalBorrow(totalAmounts_, borrowExchangePrice_);\n // ensure there is no possible case because of rounding etc. where this would revert,\n // explicitly check if >\n revenueAmount_ = revenueAmount_ > totalSupply_ ? revenueAmount_ - totalSupply_ : 0;\n // Note: if utilization > 100% (totalSupply < totalBorrow), then all the amount above 100% utilization\n // can only be revenue.\n } else {\n // if supply is 0, then rest of balance can be withdrawn as revenue so that no amounts get stuck\n revenueAmount_ = liquidityTokenBalance_;\n }\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC LIMITS /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev calculates withdrawal limit before an operate execution:\n /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n /// @param userSupplyData_ user supply data packed uint256 from storage\n /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and converted from BigMath\n /// @return currentWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction.\n /// returned value is in raw for with interest mode, normal amount for interest free mode!\n function calcWithdrawalLimitBeforeOperate(\n uint256 userSupplyData_,\n uint256 userSupply_\n ) internal view returns (uint256 currentWithdrawalLimit_) {\n // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet).\n // first tx where timestamp is 0 will enter `if (lastWithdrawalLimit_ == 0)` because lastWithdrawalLimit_ is not set yet.\n // returning max withdrawal allowed, which is not exactly right but doesn't matter because the first interaction must be\n // a deposit anyway. Important is that it would not revert.\n\n // Note the first time a deposit brings the user supply amount to above the base withdrawal limit, the active limit\n // is the fully expanded limit immediately.\n\n // extract last set withdrawal limit\n uint256 lastWithdrawalLimit_ = (userSupplyData_ >>\n LiquiditySlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) & X64;\n lastWithdrawalLimit_ =\n (lastWithdrawalLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n (lastWithdrawalLimit_ & DEFAULT_EXPONENT_MASK);\n if (lastWithdrawalLimit_ == 0) {\n // withdrawal limit is not activated. Max withdrawal allowed\n return 0;\n }\n\n uint256 maxWithdrawableLimit_;\n uint256 temp_;\n unchecked {\n // extract max withdrawable percent of user supply and\n // calculate maximum withdrawable amount expandPercentage of user supply at full expansion duration elapsed\n // e.g.: if 10% expandPercentage, meaning 10% is withdrawable after full expandDuration has elapsed.\n\n // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n maxWithdrawableLimit_ =\n (((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14) * userSupply_) /\n FOUR_DECIMALS;\n\n // time elapsed since last withdrawal limit was set (in seconds)\n // @dev last process timestamp is guaranteed to exist for withdrawal, as a supply must have happened before.\n // last timestamp can not be > current timestamp\n temp_ =\n block.timestamp -\n ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) & X33);\n }\n // calculate withdrawable amount of expandPercent that is elapsed of expandDuration.\n // e.g. if 60% of expandDuration has elapsed, then user should be able to withdraw 6% of user supply, down to 94%.\n // Note: no explicit check for this needed, it is covered by setting minWithdrawalLimit_ if needed.\n temp_ =\n (maxWithdrawableLimit_ * temp_) /\n // extract expand duration: After this, decrement won't happen (user can withdraw 100% of withdraw limit)\n ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24); // expand duration can never be 0\n // calculate expanded withdrawal limit: last withdrawal limit - withdrawable amount.\n // Note: withdrawable amount here can grow bigger than userSupply if timeElapsed is a lot bigger than expandDuration,\n // which would cause the subtraction `lastWithdrawalLimit_ - withdrawableAmount_` to revert. In that case, set 0\n // which will cause minimum (fully expanded) withdrawal limit to be set in lines below.\n unchecked {\n // underflow explicitly checked & handled\n currentWithdrawalLimit_ = lastWithdrawalLimit_ > temp_ ? lastWithdrawalLimit_ - temp_ : 0;\n // calculate minimum withdrawal limit: minimum amount of user supply that must stay supplied at full expansion.\n // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n temp_ = userSupply_ - maxWithdrawableLimit_;\n }\n // if withdrawal limit is decreased below minimum then set minimum\n // (e.g. when more than expandDuration time has elapsed)\n if (temp_ > currentWithdrawalLimit_) {\n currentWithdrawalLimit_ = temp_;\n }\n }\n\n /// @dev calculates withdrawal limit after an operate execution:\n /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n /// @param userSupplyData_ user supply data packed uint256 from storage\n /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and added / subtracted with the executed operate amount\n /// @param newWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction, result from `calcWithdrawalLimitBeforeOperate`\n /// @return withdrawalLimit_ updated withdrawal limit that should be written to storage. returned value is in\n /// raw for with interest mode, normal amount for interest free mode!\n function calcWithdrawalLimitAfterOperate(\n uint256 userSupplyData_,\n uint256 userSupply_,\n uint256 newWithdrawalLimit_\n ) internal pure returns (uint256) {\n // temp_ => base withdrawal limit. below this, maximum withdrawals are allowed\n uint256 temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n // if user supply is below base limit then max withdrawals are allowed\n if (userSupply_ < temp_) {\n return 0;\n }\n // temp_ => withdrawal limit expandPercent (is in 1e2 decimals)\n temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14;\n unchecked {\n // temp_ => minimum withdrawal limit: userSupply - max withdrawable limit (userSupply * expandPercent))\n // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n temp_ = userSupply_ - ((userSupply_ * temp_) / FOUR_DECIMALS);\n }\n // if new (before operation) withdrawal limit is less than minimum limit then set minimum limit.\n // e.g. can happen on new deposits. withdrawal limit is instantly fully expanded in a scenario where\n // increased deposit amount outpaces withrawals.\n if (temp_ > newWithdrawalLimit_) {\n return temp_;\n }\n return newWithdrawalLimit_;\n }\n\n /// @dev calculates borrow limit before an operate execution:\n /// total amount user borrow can reach (not borrowable amount in current operation).\n /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n /// @param userBorrowData_ user borrow data packed uint256 from storage\n /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_`\n /// @return currentBorrowLimit_ current borrow limit updated for expansion since last interaction. returned value is in\n /// raw for with interest mode, normal amount for interest free mode!\n function calcBorrowLimitBeforeOperate(\n uint256 userBorrowData_,\n uint256 userBorrow_\n ) internal view returns (uint256 currentBorrowLimit_) {\n // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet) -> base limit.\n // first tx where timestamp is 0 will enter `if (maxExpandedBorrowLimit_ < baseBorrowLimit_)` because `userBorrow_` and thus\n // `maxExpansionLimit_` and thus `maxExpandedBorrowLimit_` is 0 and `baseBorrowLimit_` can not be 0.\n\n // temp_ = extract borrow expand percent (is in 1e2 decimals)\n uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14;\n\n uint256 maxExpansionLimit_;\n uint256 maxExpandedBorrowLimit_;\n unchecked {\n // calculate max expansion limit: Max amount limit can expand to since last interaction\n // userBorrow_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n maxExpansionLimit_ = ((userBorrow_ * temp_) / FOUR_DECIMALS);\n\n // calculate max borrow limit: Max point limit can increase to since last interaction\n maxExpandedBorrowLimit_ = userBorrow_ + maxExpansionLimit_;\n }\n\n // currentBorrowLimit_ = extract base borrow limit\n currentBorrowLimit_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n currentBorrowLimit_ =\n (currentBorrowLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n (currentBorrowLimit_ & DEFAULT_EXPONENT_MASK);\n\n if (maxExpandedBorrowLimit_ < currentBorrowLimit_) {\n return currentBorrowLimit_;\n }\n // time elapsed since last borrow limit was set (in seconds)\n unchecked {\n // temp_ = timeElapsed_ (last timestamp can not be > current timestamp)\n temp_ =\n block.timestamp -\n ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) & X33); // extract last udpate timestamp\n }\n\n // currentBorrowLimit_ = expandedBorrowableAmount + extract last set borrow limit\n currentBorrowLimit_ =\n // calculate borrow limit expansion since last interaction for `expandPercent` that is elapsed of `expandDuration`.\n // divisor is extract expand duration (after this, full expansion to expandPercentage happened).\n ((maxExpansionLimit_ * temp_) /\n ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24)) + // expand duration can never be 0\n // extract last set borrow limit\n BigMathMinified.fromBigNumber(\n (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) & X64,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n\n // if timeElapsed is bigger than expandDuration, new borrow limit would be > max expansion,\n // so set to `maxExpandedBorrowLimit_` in that case.\n // also covers the case where last process timestamp = 0 (timeElapsed would simply be very big)\n if (currentBorrowLimit_ > maxExpandedBorrowLimit_) {\n currentBorrowLimit_ = maxExpandedBorrowLimit_;\n }\n // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n if (currentBorrowLimit_ > temp_) {\n currentBorrowLimit_ = temp_;\n }\n }\n\n /// @dev calculates borrow limit after an operate execution:\n /// total amount user borrow can reach (not borrowable amount in current operation).\n /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n /// @param userBorrowData_ user borrow data packed uint256 from storage\n /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_` and added / subtracted with the executed operate amount\n /// @param newBorrowLimit_ current borrow limit updated for expansion since last interaction, result from `calcBorrowLimitBeforeOperate`\n /// @return borrowLimit_ updated borrow limit that should be written to storage.\n /// returned value is in raw for with interest mode, normal amount for interest free mode!\n function calcBorrowLimitAfterOperate(\n uint256 userBorrowData_,\n uint256 userBorrow_,\n uint256 newBorrowLimit_\n ) internal pure returns (uint256 borrowLimit_) {\n // temp_ = extract borrow expand percent\n uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14; // (is in 1e2 decimals)\n\n unchecked {\n // borrowLimit_ = calculate maximum borrow limit at full expansion.\n // userBorrow_ needs to be at least 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n borrowLimit_ = userBorrow_ + ((userBorrow_ * temp_) / FOUR_DECIMALS);\n }\n\n // temp_ = extract base borrow limit\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n if (borrowLimit_ < temp_) {\n // below base limit, borrow limit is always base limit\n return temp_;\n }\n // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n // make sure fully expanded borrow limit is not above hard max borrow limit\n if (borrowLimit_ > temp_) {\n borrowLimit_ = temp_;\n }\n // if new borrow limit (from before operate) is > max borrow limit, set max borrow limit.\n // (e.g. on a repay shrinking instantly to fully expanded borrow limit from new borrow amount. shrinking is instant)\n if (newBorrowLimit_ > borrowLimit_) {\n return borrowLimit_;\n }\n return newBorrowLimit_;\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC RATES /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev Calculates new borrow rate from utilization for a token\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ totalBorrow / totalSupply. 1e4 = 100% utilization\n /// @return rate_ rate for that particular token in 1e2 precision (e.g. 5% rate = 500)\n function calcBorrowRateFromUtilization(uint256 rateData_, uint256 utilization_) internal returns (uint256 rate_) {\n // extract rate version: 4 bits (0xF) starting from bit 0\n uint256 rateVersion_ = (rateData_ & 0xF);\n\n if (rateVersion_ == 1) {\n rate_ = calcRateV1(rateData_, utilization_);\n } else if (rateVersion_ == 2) {\n rate_ = calcRateV2(rateData_, utilization_);\n } else {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__UnsupportedRateVersion);\n }\n\n if (rate_ > X16) {\n // hard cap for borrow rate at maximum value 16 bits (65535) to make sure it does not overflow storage space.\n // this is unlikely to ever happen if configs stay within expected levels.\n rate_ = X16;\n // emit event to more easily become aware\n emit BorrowRateMaxCap();\n }\n }\n\n /// @dev calculates the borrow rate based on utilization for rate data version 1 (with one kink) in 1e2 precision\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ in 1e2 (100% = 1e4)\n /// @return rate_ rate in 1e2 precision\n function calcRateV1(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n /// For rate v1 (one kink) ------------------------------------------------------\n /// Next 16 bits => 4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 52- 67 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Last 188 bits => 68-255 => blank, might come in use in future\n\n // y = mx + c.\n // y is borrow rate\n // x is utilization\n // m = slope (m can be 0 but never negative)\n // c is constant (c can be negative)\n\n uint256 y1_;\n uint256 y2_;\n uint256 x1_;\n uint256 x2_;\n\n // extract kink1: 16 bits (0xFFFF) starting from bit 20\n // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_UTILIZATION_AT_KINK) & X16;\n if (utilization_ < kink1_) {\n // if utilization is less than kink\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n x1_ = 0; // 0%\n x2_ = kink1_;\n } else {\n // else utilization is greater than kink\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX) & X16;\n x1_ = kink1_;\n x2_ = FOUR_DECIMALS; // 100%\n }\n\n int256 constant_;\n uint256 slope_;\n unchecked {\n // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor) and rate at y2 can not be < rate at y1\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n slope_ = ((y2_ - y1_) * TWELVE_DECIMALS) / (x2_ - x1_);\n\n // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n // subtraction most extreme case would be 0 - max value slope_ * x1_ => can not underflow int256\n constant_ = int256(y1_ * TWELVE_DECIMALS) - int256(slope_ * x1_);\n\n // calculating new borrow rate\n // - slope_ max value is 65535 * 1e12,\n // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n // - constant max value is 65535 * 1e12\n // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n // divisor TWELVE_DECIMALS can not be 0\n rate_ = (uint256(int256(slope_ * utilization_) + constant_)) / TWELVE_DECIMALS;\n }\n }\n\n /// @dev calculates the borrow rate based on utilization for rate data version 2 (with two kinks) in 1e4 precision\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ in 1e2 (100% = 1e4)\n /// @return rate_ rate in 1e4 precision\n function calcRateV2(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n /// For rate v2 (two kinks) -----------------------------------------------------\n /// Next 16 bits => 4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 52- 67 => Utilization at kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 68- 83 => Rate at utilization kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 84- 99 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Last 156 bits => 100-255 => blank, might come in use in future\n\n // y = mx + c.\n // y is borrow rate\n // x is utilization\n // m = slope (m can be 0 but never negative)\n // c is constant (c can be negative)\n\n uint256 y1_;\n uint256 y2_;\n uint256 x1_;\n uint256 x2_;\n\n // extract kink1: 16 bits (0xFFFF) starting from bit 20\n // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1) & X16;\n if (utilization_ < kink1_) {\n // if utilization is less than kink1\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n x1_ = 0; // 0%\n x2_ = kink1_;\n } else {\n // extract kink2: 16 bits (0xFFFF) starting from bit 52\n uint256 kink2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2) & X16;\n if (utilization_ < kink2_) {\n // if utilization is less than kink2\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n x1_ = kink1_;\n x2_ = kink2_;\n } else {\n // else utilization is greater than kink2\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX) & X16;\n x1_ = kink2_;\n x2_ = FOUR_DECIMALS;\n }\n }\n\n int256 constant_;\n uint256 slope_;\n unchecked {\n // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor) and rate at y2 can not be < rate at y1\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n slope_ = ((y2_ - y1_) * TWELVE_DECIMALS) / (x2_ - x1_);\n\n // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n // subtraction most extreme case would be 0 - max value slope_ * x1_ => can not underflow int256\n constant_ = int256(y1_ * TWELVE_DECIMALS) - int256(slope_ * x1_);\n\n // calculating new borrow rate\n // - slope_ max value is 65535 * 1e12,\n // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n // - constant max value is 65535 * 1e12\n // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n // divisor TWELVE_DECIMALS can not be 0\n rate_ = (uint256(int256(slope_ * utilization_) + constant_)) / TWELVE_DECIMALS;\n }\n }\n\n /// @dev reads the total supply out of Liquidity packed storage `totalAmounts_` for `supplyExchangePrice_`\n function getTotalSupply(\n uint256 totalAmounts_,\n uint256 supplyExchangePrice_\n ) internal pure returns (uint256 totalSupply_) {\n // totalSupply_ => supplyInterestFree\n totalSupply_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;\n totalSupply_ = (totalSupply_ >> DEFAULT_EXPONENT_SIZE) << (totalSupply_ & DEFAULT_EXPONENT_MASK);\n\n uint256 totalSupplyRaw_ = totalAmounts_ & X64; // no shifting as supplyRaw is first 64 bits\n totalSupplyRaw_ = (totalSupplyRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalSupplyRaw_ & DEFAULT_EXPONENT_MASK);\n\n // totalSupply = supplyInterestFree + supplyRawInterest normalized from raw\n totalSupply_ += ((totalSupplyRaw_ * supplyExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n }\n\n /// @dev reads the total borrow out of Liquidity packed storage `totalAmounts_` for `borrowExchangePrice_`\n function getTotalBorrow(\n uint256 totalAmounts_,\n uint256 borrowExchangePrice_\n ) internal pure returns (uint256 totalBorrow_) {\n // totalBorrow_ => borrowInterestFree\n // no & mask needed for borrow interest free as it occupies the last bits in the storage slot\n totalBorrow_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);\n totalBorrow_ = (totalBorrow_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrow_ & DEFAULT_EXPONENT_MASK);\n\n uint256 totalBorrowRaw_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;\n totalBorrowRaw_ = (totalBorrowRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrowRaw_ & DEFAULT_EXPONENT_MASK);\n\n // totalBorrow = borrowInterestFree + borrowRawInterest normalized from raw\n totalBorrow_ += ((totalBorrowRaw_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n }\n}\n"
|
||
},
|
||
"contracts/libraries/liquiditySlotsLink.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @notice library that helps in reading / working with storage slot data of Fluid Liquidity.\n/// @dev as all data for Fluid Liquidity is internal, any data must be fetched directly through manual\n/// slot reading through this library or, if gas usage is less important, through the FluidLiquidityResolver.\nlibrary LiquiditySlotsLink {\n /// @dev storage slot for status at Liquidity\n uint256 internal constant LIQUIDITY_STATUS_SLOT = 1;\n /// @dev storage slot for auths mapping at Liquidity\n uint256 internal constant LIQUIDITY_AUTHS_MAPPING_SLOT = 2;\n /// @dev storage slot for guardians mapping at Liquidity\n uint256 internal constant LIQUIDITY_GUARDIANS_MAPPING_SLOT = 3;\n /// @dev storage slot for user class mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_CLASS_MAPPING_SLOT = 4;\n /// @dev storage slot for exchangePricesAndConfig mapping at Liquidity\n uint256 internal constant LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT = 5;\n /// @dev storage slot for rateData mapping at Liquidity\n uint256 internal constant LIQUIDITY_RATE_DATA_MAPPING_SLOT = 6;\n /// @dev storage slot for totalAmounts mapping at Liquidity\n uint256 internal constant LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT = 7;\n /// @dev storage slot for user supply double mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT = 8;\n /// @dev storage slot for user borrow double mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT = 9;\n /// @dev storage slot for listed tokens array at Liquidity\n uint256 internal constant LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT = 10;\n\n // --------------------------------\n // @dev stacked uint256 storage slots bits position data for each:\n\n // ExchangePricesAndConfig\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATE = 0;\n uint256 internal constant BITS_EXCHANGE_PRICES_FEE = 16;\n uint256 internal constant BITS_EXCHANGE_PRICES_UTILIZATION = 30;\n uint256 internal constant BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD = 44;\n uint256 internal constant BITS_EXCHANGE_PRICES_LAST_TIMESTAMP = 58;\n uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE = 91;\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE = 155;\n uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_RATIO = 219;\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATIO = 234;\n\n // RateData:\n uint256 internal constant BITS_RATE_DATA_VERSION = 0;\n // RateData: V1\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO = 4;\n uint256 internal constant BITS_RATE_DATA_V1_UTILIZATION_AT_KINK = 20;\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK = 36;\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX = 52;\n // RateData: V2\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO = 4;\n uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1 = 20;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1 = 36;\n uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2 = 52;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2 = 68;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX = 84;\n\n // TotalAmounts\n uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_WITH_INTEREST = 0;\n uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE = 64;\n uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST = 128;\n uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE = 192;\n\n // UserSupplyData\n uint256 internal constant BITS_USER_SUPPLY_MODE = 0;\n uint256 internal constant BITS_USER_SUPPLY_AMOUNT = 1;\n uint256 internal constant BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT = 65;\n uint256 internal constant BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP = 129;\n uint256 internal constant BITS_USER_SUPPLY_EXPAND_PERCENT = 162;\n uint256 internal constant BITS_USER_SUPPLY_EXPAND_DURATION = 176;\n uint256 internal constant BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT = 200;\n uint256 internal constant BITS_USER_SUPPLY_IS_PAUSED = 255;\n\n // UserBorrowData\n uint256 internal constant BITS_USER_BORROW_MODE = 0;\n uint256 internal constant BITS_USER_BORROW_AMOUNT = 1;\n uint256 internal constant BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT = 65;\n uint256 internal constant BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP = 129;\n uint256 internal constant BITS_USER_BORROW_EXPAND_PERCENT = 162;\n uint256 internal constant BITS_USER_BORROW_EXPAND_DURATION = 176;\n uint256 internal constant BITS_USER_BORROW_BASE_BORROW_LIMIT = 200;\n uint256 internal constant BITS_USER_BORROW_MAX_BORROW_LIMIT = 218;\n uint256 internal constant BITS_USER_BORROW_IS_PAUSED = 255;\n\n // --------------------------------\n\n /// @notice Calculating the slot ID for Liquidity contract for single mapping at `slot_` for `key_`\n function calculateMappingStorageSlot(uint256 slot_, address key_) internal pure returns (bytes32) {\n return keccak256(abi.encode(key_, slot_));\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for double mapping at `slot_` for `key1_` and `key2_`\n function calculateDoubleMappingStorageSlot(\n uint256 slot_,\n address key1_,\n address key2_\n ) internal pure returns (bytes32) {\n bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));\n return keccak256(abi.encode(key2_, intermediateSlot_));\n }\n}\n"
|
||
},
|
||
"contracts/libraries/safeTransfer.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.21;\n\nimport { LibsErrorTypes as ErrorTypes } from \"./errorTypes.sol\";\n\n/// @notice provides minimalistic methods for safe transfers, e.g. ERC20 safeTransferFrom\nlibrary SafeTransfer {\n error FluidSafeTransferError(uint256 errorId_);\n\n /// @dev Transfer `amount_` of `token_` from `from_` to `to_`, spending the approval given by `from_` to the\n /// calling contract. If `token_` returns no value, non-reverting calls are assumed to be successful.\n /// Minimally modified from Solmate SafeTransferLib (address as input param for token, Custom Error):\n /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L31-L63\n function safeTransferFrom(address token_, address from_, address to_, uint256 amount_) internal {\n bool success_;\n\n /// @solidity memory-safe-assembly\n assembly {\n // Get a pointer to some free memory.\n let freeMemoryPointer := mload(0x40)\n\n // Write the abi-encoded calldata into memory, beginning with the function selector.\n mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\n mstore(add(freeMemoryPointer, 4), and(from_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"from_\" argument.\n mstore(add(freeMemoryPointer, 36), and(to_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to_\" argument.\n mstore(add(freeMemoryPointer, 68), amount_) // Append the \"amount_\" argument. Masking not required as it's a full 32 byte type.\n\n success_ := and(\n // Set success to whether the call reverted, if not we check it either\n // returned exactly 1 (can't just be non-zero data), or had no return data.\n or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.\n // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n // Counterintuitively, this call must be positioned second to the or() call in the\n // surrounding and() call or else returndatasize() will be zero during the computation.\n call(gas(), token_, 0, freeMemoryPointer, 100, 0, 32)\n )\n }\n\n if (!success_) {\n revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFromFailed);\n }\n }\n\n /// @dev Transfer `amount_` of `token_` to `to_`.\n /// If `token_` returns no value, non-reverting calls are assumed to be successful.\n /// Minimally modified from Solmate SafeTransferLib (address as input param for token, Custom Error):\n /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L65-L95\n function safeTransfer(address token_, address to_, uint256 amount_) internal {\n bool success_;\n\n /// @solidity memory-safe-assembly\n assembly {\n // Get a pointer to some free memory.\n let freeMemoryPointer := mload(0x40)\n\n // Write the abi-encoded calldata into memory, beginning with the function selector.\n mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n mstore(add(freeMemoryPointer, 4), and(to_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to_\" argument.\n mstore(add(freeMemoryPointer, 36), amount_) // Append the \"amount_\" argument. Masking not required as it's a full 32 byte type.\n\n success_ := and(\n // Set success to whether the call reverted, if not we check it either\n // returned exactly 1 (can't just be non-zero data), or had no return data.\n or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n // Counterintuitively, this call must be positioned second to the or() call in the\n // surrounding and() call or else returndatasize() will be zero during the computation.\n call(gas(), token_, 0, freeMemoryPointer, 68, 0, 32)\n )\n }\n\n if (!success_) {\n revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFailed);\n }\n }\n\n /// @dev Transfer `amount_` of ` native token to `to_`.\n /// Minimally modified from Solmate SafeTransferLib (Custom Error):\n /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L15-L25\n function safeTransferNative(address to_, uint256 amount_) internal {\n bool success_;\n\n /// @solidity memory-safe-assembly\n assembly {\n // Transfer the ETH and store if it succeeded or not.\n success_ := call(gas(), to_, amount_, 0, 0, 0, 0)\n }\n\n if (!success_) {\n revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFailed);\n }\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/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/mocks/mockERC721.sol": {
|
||
"content": "pragma solidity 0.8.21;\n\nimport { IERC721Enumerable } from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol\";\n\ncontract MockonERC721Received {\n error ERC721Error();\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4) {\n if (data.length != 0) {\n address owner = abi.decode(data, (address));\n\n require(owner == operator, \"owner-not-same\");\n if (operator != from) revert ERC721Error();\n\n address child = address(new MockonERC721ReceivedChild());\n\n // Transfer to Child contract\n IERC721Enumerable(msg.sender).safeTransferFrom(address(this), child, tokenId, data);\n\n // Transfer to owner back.\n IERC721Enumerable(msg.sender).safeTransferFrom(address(this), operator, tokenId);\n }\n\n return MockonERC721Received(address(this)).onERC721Received.selector;\n }\n}\n\ncontract MockonERC721ReceivedChild {\n error ERC721Error();\n\n address immutable FACTORY;\n constructor () {\n FACTORY = msg.sender;\n }\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4) {\n (address toTransfer) = abi.decode(data, (address));\n\n if (operator != from) revert ERC721Error();\n\n IERC721Enumerable(msg.sender).safeTransferFrom(address(this), FACTORY, tokenId);\n\n return MockonERC721Received(address(this)).onERC721Received.selector;\n }\n}\n\n"
|
||
},
|
||
"contracts/oracle/error.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Error {\n error FluidOracleError(uint256 errorId_);\n}\n"
|
||
},
|
||
"contracts/oracle/errorTypes.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | UniV3CheckCLRSOracle | \n |__________________________________*/\n\n /// @notice thrown when the delta between main price source and check rate source is exceeding the allowed delta\n uint256 internal constant UniV3CheckCLRSOracle__InvalidPrice = 60001;\n\n /// @notice thrown when an invalid parameter is passed to a method\n uint256 internal constant UniV3CheckCLRSOracle__InvalidParams = 60002;\n\n /// @notice thrown when the exchange rate is zero, even after all possible fallbacks depending on config\n uint256 internal constant UniV3CheckCLRSOracle__ExchangeRateZero = 60003;\n\n /***********************************|\n | Chainlink Oracle | \n |__________________________________*/\n\n /// @notice thrown when an invalid parameter is passed to a method\n uint256 internal constant ChainlinkOracle__InvalidParams = 61001;\n\n /***********************************|\n | UniswapV3 Oracle | \n |__________________________________*/\n\n /// @notice thrown when an invalid parameter is passed to a method\n uint256 internal constant UniV3Oracle__InvalidParams = 62001;\n\n /// @notice thrown when constructor is called with invalid ordered seconds agos values\n uint256 internal constant UniV3Oracle__InvalidSecondsAgos = 62002;\n\n /// @notice thrown when constructor is called with invalid delta values > 100%\n uint256 internal constant UniV3Oracle__InvalidDeltas = 62003;\n\n /***********************************|\n | WstETh Oracle | \n |__________________________________*/\n\n /// @notice thrown when an invalid parameter is passed to a method\n uint256 internal constant WstETHOracle__InvalidParams = 63001;\n\n /***********************************|\n | Redstone Oracle | \n |__________________________________*/\n\n /// @notice thrown when an invalid parameter is passed to a method\n uint256 internal constant RedstoneOracle__InvalidParams = 64001;\n\n /***********************************|\n | Fallback Oracle | \n |__________________________________*/\n\n /// @notice thrown when an invalid parameter is passed to a method\n uint256 internal constant FallbackOracle__InvalidParams = 65001;\n\n /***********************************|\n | FallbackCLRSOracle | \n |__________________________________*/\n\n /// @notice thrown when the exchange rate is zero, even for the fallback oracle source (if enabled)\n uint256 internal constant FallbackCLRSOracle__ExchangeRateZero = 66001;\n\n /***********************************|\n | WstETHCLRSOracle | \n |__________________________________*/\n\n /// @notice thrown when the exchange rate is zero, even for the fallback oracle source (if enabled)\n uint256 internal constant WstETHCLRSOracle__ExchangeRateZero = 67001;\n\n /***********************************|\n | CLFallbackUniV3Oracle | \n |__________________________________*/\n\n /// @notice thrown when the exchange rate is zero, even for the uniV3 rate\n uint256 internal constant CLFallbackUniV3Oracle__ExchangeRateZero = 68001;\n\n /***********************************|\n | WstETHCLRS2UniV3CheckCLRSOracle | \n |__________________________________*/\n\n /// @notice thrown when the exchange rate is zero, even for the uniV3 rate\n uint256 internal constant WstETHCLRS2UniV3CheckCLRSOracle__ExchangeRateZero = 69001;\n}\n"
|
||
},
|
||
"contracts/oracle/fluidOracle.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidOracle } from \"./interfaces/iFluidOracle.sol\";\n\n/// @title FluidOracle\n/// @notice Base contract that any Fluid Oracle must implement\nabstract contract FluidOracle is IFluidOracle {\n /// @inheritdoc IFluidOracle\n function getExchangeRate() external view virtual returns (uint256 exchangeRate_);\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/chainlinkOracleImpl.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IChainlinkAggregatorV3 } from \"../interfaces/external/IChainlinkAggregatorV3.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { ChainlinkStructs } from \"./structs.sol\";\n\n/// @title Chainlink Oracle implementation\n/// @notice This contract is used to get the exchange rate via up to 3 hops at Chainlink price feeds.\n/// The rate is multiplied with the previous rate at each hop.\n/// E.g. to go from wBTC to USDC (assuming rates for example):\n/// 1. wBTC -> BTC https://data.chain.link/ethereum/mainnet/crypto-other/wbtc-btc, rate: 0.92.\n/// 2. BTC -> USD https://data.chain.link/ethereum/mainnet/crypto-usd/btc-usd rate: 30,000.\n/// 3. USD -> USDC https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd rate: 0.98. Must invert feed: 1.02\n/// finale rate would be: 0.92 * 30,000 * 1.02 = 28,152\nabstract contract ChainlinkOracleImpl is OracleError, ChainlinkStructs {\n /// @notice Chainlink price feed 1 to check for the exchange rate\n IChainlinkAggregatorV3 internal immutable _CHAINLINK_FEED1;\n /// @notice Chainlink price feed 2 to check for the exchange rate\n IChainlinkAggregatorV3 internal immutable _CHAINLINK_FEED2;\n /// @notice Chainlink price feed 3 to check for the exchange rate\n IChainlinkAggregatorV3 internal immutable _CHAINLINK_FEED3;\n\n /// @notice Flag to invert the price or not for feed 1 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _CHAINLINK_INVERT_RATE1;\n /// @notice Flag to invert the price or not for feed 2 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _CHAINLINK_INVERT_RATE2;\n /// @notice Flag to invert the price or not for feed 3 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _CHAINLINK_INVERT_RATE3;\n\n /// @notice constant value for price scaling to reduce gas usage for feed 1\n uint256 internal immutable _CHAINLINK_PRICE_SCALER_MULTIPLIER1;\n /// @notice constant value for inverting price to reduce gas usage for feed 1\n uint256 internal immutable _CHAINLINK_INVERT_PRICE_DIVIDEND1;\n\n /// @notice constant value for price scaling to reduce gas usage for feed 2\n uint256 internal immutable _CHAINLINK_PRICE_SCALER_MULTIPLIER2;\n /// @notice constant value for inverting price to reduce gas usage for feed 2\n uint256 internal immutable _CHAINLINK_INVERT_PRICE_DIVIDEND2;\n\n /// @notice constant value for price scaling to reduce gas usage for feed 3\n uint256 internal immutable _CHAINLINK_PRICE_SCALER_MULTIPLIER3;\n /// @notice constant value for inverting price to reduce gas usage for feed 3\n uint256 internal immutable _CHAINLINK_INVERT_PRICE_DIVIDEND3;\n\n /// @notice constructor sets the Chainlink price feed and invertRate flag for each hop.\n /// E.g. `invertRate_` should be true if for the USDC/ETH pool it's expected that the oracle returns USDC per 1 ETH\n constructor(ChainlinkConstructorParams memory params_) {\n if (\n (params_.hops < 1 || params_.hops > 3) || // hops must be 1, 2 or 3\n (address(params_.feed1.feed) == address(0) || params_.feed1.token0Decimals == 0) || // first feed must always be defined\n (params_.hops > 1 && (address(params_.feed2.feed) == address(0) || params_.feed2.token0Decimals == 0)) || // if hops > 1, feed 2 must be defined\n (params_.hops > 2 && (address(params_.feed3.feed) == address(0) || params_.feed3.token0Decimals == 0)) // if hops > 2, feed 3 must be defined\n ) {\n revert FluidOracleError(ErrorTypes.ChainlinkOracle__InvalidParams);\n }\n\n _CHAINLINK_FEED1 = params_.feed1.feed;\n _CHAINLINK_FEED2 = params_.feed2.feed;\n _CHAINLINK_FEED3 = params_.feed3.feed;\n\n _CHAINLINK_INVERT_RATE1 = params_.feed1.invertRate;\n _CHAINLINK_INVERT_RATE2 = params_.feed2.invertRate;\n _CHAINLINK_INVERT_RATE3 = params_.feed3.invertRate;\n\n // Actual desired output rate example USDC/ETH (6 decimals / 18 decimals).\n // Note ETH has 12 decimals more than USDC.\n // 0.000515525322211842331991619857165357691 // 39 decimals. ETH for 1 USDC\n // 1954.190000000000433 // 15 decimals. USDC for 1 ETH\n\n // to get to PRICE_SCLAER_MULTIPLIER and INVERT_PRICE_DIVIDEND:\n // fetched Chainlink price is in token1Decimals per 1 token0Decimals.\n // E.g. for an USDC/ETH price feed it's in ETH 18 decimals.\n // for an BTC/USD price feed it's in USD 8 decimals.\n // So to scale to 1e27 we need to multiply by 1e27 - token0Decimals.\n // E.g. for USDC/ETH it would be: fetchedPrice * 1e21\n //\n // or for inverted (x token0 per 1 token1), formula would be:\n // = 1e27 * 10**token0Decimals / fetchedPrice\n // E.g. for USDC/ETH it would be: 1e33 / fetchedPrice\n\n // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n _CHAINLINK_PRICE_SCALER_MULTIPLIER1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed1.token0Decimals);\n _CHAINLINK_INVERT_PRICE_DIVIDEND1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed1.token0Decimals);\n\n _CHAINLINK_PRICE_SCALER_MULTIPLIER2 = params_.hops > 1\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed2.token0Decimals)\n : 1;\n _CHAINLINK_INVERT_PRICE_DIVIDEND2 = params_.hops > 1\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed2.token0Decimals)\n : 1;\n\n _CHAINLINK_PRICE_SCALER_MULTIPLIER3 = params_.hops > 2\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed3.token0Decimals)\n : 1;\n _CHAINLINK_INVERT_PRICE_DIVIDEND3 = params_.hops > 2\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed3.token0Decimals)\n : 1;\n }\n\n /// @dev Get the exchange rate from Chainlike oracle price feed(s)\n /// @return rate_ The exchange rate in `OracleUtils.RATE_OUTPUT_DECIMALS`\n function _getChainlinkExchangeRate() internal view returns (uint256 rate_) {\n rate_ = _readFeedRate(\n _CHAINLINK_FEED1,\n _CHAINLINK_INVERT_RATE1,\n _CHAINLINK_PRICE_SCALER_MULTIPLIER1,\n _CHAINLINK_INVERT_PRICE_DIVIDEND1\n );\n if (rate_ == 0 || address(_CHAINLINK_FEED2) == address(0)) {\n // rate 0 or only 1 hop -> return rate of price feed 1\n return rate_;\n }\n rate_ =\n (rate_ *\n _readFeedRate(\n _CHAINLINK_FEED2,\n _CHAINLINK_INVERT_RATE2,\n _CHAINLINK_PRICE_SCALER_MULTIPLIER2,\n _CHAINLINK_INVERT_PRICE_DIVIDEND2\n )) /\n (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n\n if (rate_ == 0 || address(_CHAINLINK_FEED3) == address(0)) {\n // rate 0 or 2 hops -> return rate of feed 1 combined with feed 2\n return rate_;\n }\n\n // 3 hops -> return rate of feed 1 combined with feed 2 & feed 3\n rate_ =\n (rate_ *\n _readFeedRate(\n _CHAINLINK_FEED3,\n _CHAINLINK_INVERT_RATE3,\n _CHAINLINK_PRICE_SCALER_MULTIPLIER3,\n _CHAINLINK_INVERT_PRICE_DIVIDEND3\n )) /\n (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n }\n\n /// @dev reads the exchange `rate_` from a Chainlink price `feed_` taking into account scaling and `invertRate_`\n function _readFeedRate(\n IChainlinkAggregatorV3 feed_,\n bool invertRate_,\n uint256 priceMultiplier_,\n uint256 invertDividend_\n ) private view returns (uint256 rate_) {\n try feed_.latestRoundData() returns (uint80, int256 exchangeRate_, uint256, uint256, uint80) {\n // Return the price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n if (invertRate_) {\n return invertDividend_ / uint256(exchangeRate_);\n } else {\n return uint256(exchangeRate_) * priceMultiplier_;\n }\n } catch {\n return 0;\n }\n }\n\n /// @notice returns all Chainlink oracle related data as utility for easy off-chain use / block explorer in a single view method\n function chainlinkOracleData()\n public\n view\n returns (\n uint256 chainlinkExchangeRate_,\n IChainlinkAggregatorV3 chainlinkFeed1_,\n bool chainlinkInvertRate1_,\n uint256 chainlinkExchangeRate1_,\n IChainlinkAggregatorV3 chainlinkFeed2_,\n bool chainlinkInvertRate2_,\n uint256 chainlinkExchangeRate2_,\n IChainlinkAggregatorV3 chainlinkFeed3_,\n bool chainlinkInvertRate3_,\n uint256 chainlinkExchangeRate3_\n )\n {\n return (\n _getChainlinkExchangeRate(),\n _CHAINLINK_FEED1,\n _CHAINLINK_INVERT_RATE1,\n _readFeedRate(\n _CHAINLINK_FEED1,\n _CHAINLINK_INVERT_RATE1,\n _CHAINLINK_PRICE_SCALER_MULTIPLIER1,\n _CHAINLINK_INVERT_PRICE_DIVIDEND1\n ),\n _CHAINLINK_FEED2,\n _CHAINLINK_INVERT_RATE2,\n address(_CHAINLINK_FEED2) == address(0)\n ? 0\n : _readFeedRate(\n _CHAINLINK_FEED2,\n _CHAINLINK_INVERT_RATE2,\n _CHAINLINK_PRICE_SCALER_MULTIPLIER2,\n _CHAINLINK_INVERT_PRICE_DIVIDEND2\n ),\n _CHAINLINK_FEED3,\n _CHAINLINK_INVERT_RATE3,\n address(_CHAINLINK_FEED3) == address(0)\n ? 0\n : _readFeedRate(\n _CHAINLINK_FEED3,\n _CHAINLINK_INVERT_RATE3,\n _CHAINLINK_PRICE_SCALER_MULTIPLIER3,\n _CHAINLINK_INVERT_PRICE_DIVIDEND3\n )\n );\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/chainlinkOracleImpl2.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IChainlinkAggregatorV3 } from \"../interfaces/external/IChainlinkAggregatorV3.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { ChainlinkStructs } from \"./structs.sol\";\n\n// @dev Exact same contract as ChainlinkOracleImpl, just with all vars, immutables etc. renamed with a \"2\" to avoid\n// conflicts when ChainlinkOracleImpl would have to be inherited twice.\n\n/// @title Chainlink Oracle implementation.\n/// @notice This contract is used to get the exchange rate via up to 3 hops at Chainlink price feeds.\n/// The rate is multiplied with the previous rate at each hop.\n/// E.g. to go from wBTC to USDC (assuming rates for example):\n/// 1. wBTC -> BTC https://data.chain.link/ethereum/mainnet/crypto-other/wbtc-btc, rate: 0.92.\n/// 2. BTC -> USD https://data.chain.link/ethereum/mainnet/crypto-usd/btc-usd rate: 30,000.\n/// 3. USD -> USDC https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd rate: 0.98. Must invert feed: 1.02\n/// finale rate would be: 0.92 * 30,000 * 1.02 = 28,152\nabstract contract ChainlinkOracleImpl2 is OracleError, ChainlinkStructs {\n /// @notice Chainlink price feed 1 to check for the exchange rate\n IChainlinkAggregatorV3 internal immutable _CHAINLINK2_FEED1;\n /// @notice Chainlink price feed 2 to check for the exchange rate\n IChainlinkAggregatorV3 internal immutable _CHAINLINK2_FEED2;\n /// @notice Chainlink price feed 3 to check for the exchange rate\n IChainlinkAggregatorV3 internal immutable _CHAINLINK2_FEED3;\n\n /// @notice Flag to invert the price or not for feed 1 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _CHAINLINK2_INVERT_RATE1;\n /// @notice Flag to invert the price or not for feed 2 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _CHAINLINK2_INVERT_RATE2;\n /// @notice Flag to invert the price or not for feed 3 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _CHAINLINK2_INVERT_RATE3;\n\n /// @notice constant value for price scaling to reduce gas usage for feed 1\n uint256 internal immutable _CHAINLINK2_PRICE_SCALER_MULTIPLIER1;\n /// @notice constant value for inverting price to reduce gas usage for feed 1\n uint256 internal immutable _CHAINLINK2_INVERT_PRICE_DIVIDEND1;\n\n /// @notice constant value for price scaling to reduce gas usage for feed 2\n uint256 internal immutable _CHAINLINK2_PRICE_SCALER_MULTIPLIER2;\n /// @notice constant value for inverting price to reduce gas usage for feed 2\n uint256 internal immutable _CHAINLINK2_INVERT_PRICE_DIVIDEND2;\n\n /// @notice constant value for price scaling to reduce gas usage for feed 3\n uint256 internal immutable _CHAINLINK2_PRICE_SCALER_MULTIPLIER3;\n /// @notice constant value for inverting price to reduce gas usage for feed 3\n uint256 internal immutable _CHAINLINK2_INVERT_PRICE_DIVIDEND3;\n\n /// @notice constructor sets the Chainlink price feed and invertRate flag for each hop.\n /// E.g. `invertRate_` should be true if for the USDC/ETH pool it's expected that the oracle returns USDC per 1 ETH\n constructor(ChainlinkConstructorParams memory params_) {\n if (\n (params_.hops < 1 || params_.hops > 3) || // hops must be 1, 2 or 3\n (address(params_.feed1.feed) == address(0) || params_.feed1.token0Decimals == 0) || // first feed must always be defined\n (params_.hops > 1 && (address(params_.feed2.feed) == address(0) || params_.feed2.token0Decimals == 0)) || // if hops > 1, feed 2 must be defined\n (params_.hops > 2 && (address(params_.feed3.feed) == address(0) || params_.feed3.token0Decimals == 0)) // if hops > 2, feed 3 must be defined\n ) {\n revert FluidOracleError(ErrorTypes.ChainlinkOracle__InvalidParams);\n }\n\n _CHAINLINK2_FEED1 = params_.feed1.feed;\n _CHAINLINK2_FEED2 = params_.feed2.feed;\n _CHAINLINK2_FEED3 = params_.feed3.feed;\n\n _CHAINLINK2_INVERT_RATE1 = params_.feed1.invertRate;\n _CHAINLINK2_INVERT_RATE2 = params_.feed2.invertRate;\n _CHAINLINK2_INVERT_RATE3 = params_.feed3.invertRate;\n\n // Actual desired output rate example USDC/ETH (6 decimals / 18 decimals).\n // Note ETH has 12 decimals more than USDC.\n // 0.000515525322211842331991619857165357691 // 39 decimals. ETH for 1 USDC\n // 1954.190000000000433 // 15 decimals. USDC for 1 ETH\n\n // to get to PRICE_SCLAER_MULTIPLIER and INVERT_PRICE_DIVIDEND:\n // fetched Chainlink price is in token1Decimals per 1 token0Decimals.\n // E.g. for an USDC/ETH price feed it's in ETH 18 decimals.\n // for an BTC/USD price feed it's in USD 8 decimals.\n // So to scale to 1e27 we need to multiply by 1e27 - token0Decimals.\n // E.g. for USDC/ETH it would be: fetchedPrice * 1e21\n //\n // or for inverted (x token0 per 1 token1), formula would be:\n // = 1e27 * 10**token0Decimals / fetchedPrice\n // E.g. for USDC/ETH it would be: 1e33 / fetchedPrice\n\n // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed1.token0Decimals);\n _CHAINLINK2_INVERT_PRICE_DIVIDEND1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed1.token0Decimals);\n\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER2 = params_.hops > 1\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed2.token0Decimals)\n : 1;\n _CHAINLINK2_INVERT_PRICE_DIVIDEND2 = params_.hops > 1\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed2.token0Decimals)\n : 1;\n\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER3 = params_.hops > 2\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed3.token0Decimals)\n : 1;\n _CHAINLINK2_INVERT_PRICE_DIVIDEND3 = params_.hops > 2\n ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed3.token0Decimals)\n : 1;\n }\n\n /// @dev Get the exchange rate from Chainlike oracle price feed(s)\n /// @return rate_ The exchange rate in `OracleUtils.RATE_OUTPUT_DECIMALS`\n function _getChainlinkExchangeRate2() internal view returns (uint256 rate_) {\n rate_ = _readFeedRate2(\n _CHAINLINK2_FEED1,\n _CHAINLINK2_INVERT_RATE1,\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER1,\n _CHAINLINK2_INVERT_PRICE_DIVIDEND1\n );\n if (rate_ == 0 || address(_CHAINLINK2_FEED2) == address(0)) {\n // rate 0 or only 1 hop -> return rate of price feed 1\n return rate_;\n }\n rate_ =\n (rate_ *\n _readFeedRate2(\n _CHAINLINK2_FEED2,\n _CHAINLINK2_INVERT_RATE2,\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER2,\n _CHAINLINK2_INVERT_PRICE_DIVIDEND2\n )) /\n (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n\n if (rate_ == 0 || address(_CHAINLINK2_FEED3) == address(0)) {\n // rate 0 or 2 hops -> return rate of feed 1 combined with feed 2\n return rate_;\n }\n\n // 3 hops -> return rate of feed 1 combined with feed 2 & feed 3\n rate_ =\n (rate_ *\n _readFeedRate2(\n _CHAINLINK2_FEED3,\n _CHAINLINK2_INVERT_RATE3,\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER3,\n _CHAINLINK2_INVERT_PRICE_DIVIDEND3\n )) /\n (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n }\n\n /// @dev reads the exchange `rate_` from a Chainlink price `feed_` taking into account scaling and `invertRate_`\n function _readFeedRate2(\n IChainlinkAggregatorV3 feed_,\n bool invertRate_,\n uint256 priceMultiplier_,\n uint256 invertDividend_\n ) private view returns (uint256 rate_) {\n try feed_.latestRoundData() returns (uint80, int256 exchangeRate_, uint256, uint256, uint80) {\n // Return the price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n if (invertRate_) {\n return invertDividend_ / uint256(exchangeRate_);\n } else {\n return uint256(exchangeRate_) * priceMultiplier_;\n }\n } catch {\n return 0;\n }\n }\n\n /// @notice returns all Chainlink oracle related data as utility for easy off-chain use / block explorer in a single view method\n function chainlinkOracleData2()\n public\n view\n returns (\n uint256 chainlinkExchangeRate_,\n IChainlinkAggregatorV3 chainlinkFeed1_,\n bool chainlinkInvertRate1_,\n uint256 chainlinkExchangeRate1_,\n IChainlinkAggregatorV3 chainlinkFeed2_,\n bool chainlinkInvertRate2_,\n uint256 chainlinkExchangeRate2_,\n IChainlinkAggregatorV3 chainlinkFeed3_,\n bool chainlinkInvertRate3_,\n uint256 chainlinkExchangeRate3_\n )\n {\n return (\n _getChainlinkExchangeRate2(),\n _CHAINLINK2_FEED1,\n _CHAINLINK2_INVERT_RATE1,\n _readFeedRate2(\n _CHAINLINK2_FEED1,\n _CHAINLINK2_INVERT_RATE1,\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER1,\n _CHAINLINK2_INVERT_PRICE_DIVIDEND1\n ),\n _CHAINLINK2_FEED2,\n _CHAINLINK2_INVERT_RATE2,\n address(_CHAINLINK2_FEED2) == address(0)\n ? 0\n : _readFeedRate2(\n _CHAINLINK2_FEED2,\n _CHAINLINK2_INVERT_RATE2,\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER2,\n _CHAINLINK2_INVERT_PRICE_DIVIDEND2\n ),\n _CHAINLINK2_FEED3,\n _CHAINLINK2_INVERT_RATE3,\n address(_CHAINLINK2_FEED3) == address(0)\n ? 0\n : _readFeedRate2(\n _CHAINLINK2_FEED3,\n _CHAINLINK2_INVERT_RATE3,\n _CHAINLINK2_PRICE_SCALER_MULTIPLIER3,\n _CHAINLINK2_INVERT_PRICE_DIVIDEND3\n )\n );\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/fallbackOracleImpl.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { ChainlinkOracleImpl } from \"./chainlinkOracleImpl.sol\";\nimport { RedstoneOracleImpl } from \"./redstoneOracleImpl.sol\";\n\n/// @title Fallback Oracle implementation\n/// @notice This contract is used to get the exchange rate from a main oracle feed and a fallback oracle feed.\n//\n// @dev inheriting contracts should implement a view method to expose `_FALLBACK_ORACLE_MAIN_SOURCE`\nabstract contract FallbackOracleImpl is OracleError, RedstoneOracleImpl, ChainlinkOracleImpl {\n /// @dev which oracle to use as main source:\n /// - 1 = Chainlink ONLY (no fallback)\n /// - 2 = Chainlink with Redstone Fallback\n /// - 3 = Redstone with Chainlink Fallback\n uint8 internal immutable _FALLBACK_ORACLE_MAIN_SOURCE;\n\n /// @notice sets the main source, Chainlink Oracle and Redstone Oracle data.\n /// @param mainSource_ which oracle to use as main source:\n /// - 1 = Chainlink ONLY (no fallback)\n /// - 2 = Chainlink with Redstone Fallback\n /// - 3 = Redstone with Chainlink Fallback\n /// @param chainlinkParams_ chainlink Oracle constructor params struct.\n /// @param redstoneOracle_ Redstone Oracle data. (address can be set to zero address if using Chainlink only)\n constructor(\n uint8 mainSource_,\n ChainlinkConstructorParams memory chainlinkParams_,\n RedstoneOracleData memory redstoneOracle_\n )\n ChainlinkOracleImpl(chainlinkParams_)\n RedstoneOracleImpl(\n address(redstoneOracle_.oracle) == address(0)\n ? RedstoneOracleData(IRedstoneOracle(_REDSTONE_ORACLE_NOT_SET_ADDRESS), false, 1)\n : redstoneOracle_\n )\n {\n if (mainSource_ < 1 || mainSource_ > 3) {\n revert FluidOracleError(ErrorTypes.FallbackOracle__InvalidParams);\n }\n _FALLBACK_ORACLE_MAIN_SOURCE = mainSource_;\n }\n\n /// @dev returns the exchange rate for the main oracle source, or the fallback source (if configured) if the main exchange rate\n /// fails to be fetched. If returned rate is 0, fetching rate failed or something went wrong.\n /// @return exchangeRate_ exchange rate\n /// @return fallback_ whether fallback was necessary or not\n function _getRateWithFallback() internal view returns (uint256 exchangeRate_, bool fallback_) {\n if (_FALLBACK_ORACLE_MAIN_SOURCE == 1) {\n // 1 = Chainlink ONLY (no fallback)\n exchangeRate_ = _getChainlinkExchangeRate();\n } else if (_FALLBACK_ORACLE_MAIN_SOURCE == 2) {\n // 2 = Chainlink with Redstone Fallback\n exchangeRate_ = _getChainlinkExchangeRate();\n if (exchangeRate_ == 0) {\n fallback_ = true;\n exchangeRate_ = _getRedstoneExchangeRate();\n }\n } else {\n // 3 = Redstone with Chainlink Fallback\n exchangeRate_ = _getRedstoneExchangeRate();\n if (exchangeRate_ == 0) {\n fallback_ = true;\n exchangeRate_ = _getChainlinkExchangeRate();\n }\n }\n }\n\n /// @dev returns the exchange rate for Chainlink, or Redstone if configured & Chainlink fails.\n function _getChainlinkOrRedstoneAsFallback() internal view returns (uint256 exchangeRate_) {\n exchangeRate_ = _getChainlinkExchangeRate();\n\n if (exchangeRate_ == 0 && _FALLBACK_ORACLE_MAIN_SOURCE != 1) {\n // Chainlink failed but Redstone is configured too -> try Redstone\n exchangeRate_ = _getRedstoneExchangeRate();\n }\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/fallbackOracleImpl2.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { ChainlinkOracleImpl2 } from \"./chainlinkOracleImpl2.sol\";\nimport { RedstoneOracleImpl2 } from \"./redstoneOracleImpl2.sol\";\n\n// @dev Exact same contract as FallbackOracleImpl, just with all vars, immutables etc. renamed with a \"2\" and inheriting\n// to ChainlinkOracleImpl2 and RedstoneOracleImpl2 to avoid conflicts when FallbackOracleImpl would have to be inherited twice.\n\n/// @title Fallback Oracle implementation\n/// @notice This contract is used to get the exchange rate from a main oracle feed and a fallback oracle feed.\n//\n// @dev inheriting contracts should implement a view method to expose `_FALLBACK_ORACLE2_MAIN_SOURCE`\nabstract contract FallbackOracleImpl2 is OracleError, RedstoneOracleImpl2, ChainlinkOracleImpl2 {\n /// @dev which oracle to use as main source:\n /// - 1 = Chainlink ONLY (no fallback)\n /// - 2 = Chainlink with Redstone Fallback\n /// - 3 = Redstone with Chainlink Fallback\n uint8 internal immutable _FALLBACK_ORACLE2_MAIN_SOURCE;\n\n /// @notice sets the main source, Chainlink Oracle and Redstone Oracle data.\n /// @param mainSource_ which oracle to use as main source:\n /// - 1 = Chainlink ONLY (no fallback)\n /// - 2 = Chainlink with Redstone Fallback\n /// - 3 = Redstone with Chainlink Fallback\n /// @param chainlinkParams_ chainlink Oracle constructor params struct.\n /// @param redstoneOracle_ Redstone Oracle data. (address can be set to zero address if using Chainlink only)\n constructor(\n uint8 mainSource_,\n ChainlinkConstructorParams memory chainlinkParams_,\n RedstoneOracleData memory redstoneOracle_\n )\n ChainlinkOracleImpl2(chainlinkParams_)\n RedstoneOracleImpl2(\n address(redstoneOracle_.oracle) == address(0)\n ? RedstoneOracleData(IRedstoneOracle(_REDSTONE2_ORACLE_NOT_SET_ADDRESS), false, 1)\n : redstoneOracle_\n )\n {\n if (mainSource_ < 1 || mainSource_ > 3) {\n revert FluidOracleError(ErrorTypes.FallbackOracle__InvalidParams);\n }\n _FALLBACK_ORACLE2_MAIN_SOURCE = mainSource_;\n }\n\n /// @dev returns the exchange rate for the main oracle source, or the fallback source (if configured) if the main exchange rate\n /// fails to be fetched. If returned rate is 0, fetching rate failed or something went wrong.\n /// @return exchangeRate_ exchange rate\n /// @return fallback_ whether fallback was necessary or not\n function _getRateWithFallback2() internal view returns (uint256 exchangeRate_, bool fallback_) {\n if (_FALLBACK_ORACLE2_MAIN_SOURCE == 1) {\n // 1 = Chainlink ONLY (no fallback)\n exchangeRate_ = _getChainlinkExchangeRate2();\n } else if (_FALLBACK_ORACLE2_MAIN_SOURCE == 2) {\n // 2 = Chainlink with Redstone Fallback\n exchangeRate_ = _getChainlinkExchangeRate2();\n if (exchangeRate_ == 0) {\n fallback_ = true;\n exchangeRate_ = _getRedstoneExchangeRate2();\n }\n } else {\n // 3 = Redstone with Chainlink Fallback\n exchangeRate_ = _getRedstoneExchangeRate2();\n if (exchangeRate_ == 0) {\n fallback_ = true;\n exchangeRate_ = _getChainlinkExchangeRate2();\n }\n }\n }\n\n /// @dev returns the exchange rate for Chainlink, or Redstone if configured & Chainlink fails.\n function _getChainlinkOrRedstoneAsFallback2() internal view returns (uint256 exchangeRate_) {\n exchangeRate_ = _getChainlinkExchangeRate2();\n\n if (exchangeRate_ == 0 && _FALLBACK_ORACLE2_MAIN_SOURCE != 1) {\n // Chainlink failed but Redstone is configured too -> try Redstone\n exchangeRate_ = _getRedstoneExchangeRate2();\n }\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/redstoneOracleImpl.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { RedstoneStructs } from \"./structs.sol\";\n\n/// @title Redstone Oracle implementation\n/// @notice This contract is used to get the exchange rate from a Redstone Oracle\nabstract contract RedstoneOracleImpl is OracleError, RedstoneStructs {\n /// @notice Redstone price oracle to check for the exchange rate\n IRedstoneOracle internal immutable _REDSTONE_ORACLE;\n /// @notice Flag to invert the price or not (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _REDSTONE_INVERT_RATE;\n\n /// @notice constant value for price scaling to reduce gas usage\n uint256 internal immutable _REDSTONE_PRICE_SCALER_MULTIPLIER;\n /// @notice constant value for inverting price to reduce gas usage\n uint256 internal immutable _REDSTONE_INVERT_PRICE_DIVIDEND;\n\n address internal immutable _REDSTONE_ORACLE_NOT_SET_ADDRESS = 0x000000000000000000000000000000000000dEaD;\n\n /// @notice constructor sets the Redstone oracle data\n constructor(RedstoneOracleData memory oracleData_) {\n if (address(oracleData_.oracle) == address(0) || oracleData_.token0Decimals == 0) {\n revert FluidOracleError(ErrorTypes.RedstoneOracle__InvalidParams);\n }\n\n _REDSTONE_ORACLE = oracleData_.oracle;\n _REDSTONE_INVERT_RATE = oracleData_.invertRate;\n\n // for explanation on how to get to scaler multiplier and dividend see `chainlinkOracleImpl.sol`.\n // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n _REDSTONE_PRICE_SCALER_MULTIPLIER = address(oracleData_.oracle) == _REDSTONE_ORACLE_NOT_SET_ADDRESS\n ? 1\n : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - oracleData_.token0Decimals);\n _REDSTONE_INVERT_PRICE_DIVIDEND = address(oracleData_.oracle) == _REDSTONE_ORACLE_NOT_SET_ADDRESS\n ? 1\n : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + oracleData_.token0Decimals);\n }\n\n /// @dev Get the exchange rate from Redstone oracle\n /// @param rate_ The exchange rate in `_REDSTONE_OUTPUT_DECIMALS`\n function _getRedstoneExchangeRate() internal view returns (uint256 rate_) {\n try _REDSTONE_ORACLE.getExchangeRate() returns (uint256 exchangeRate_) {\n // Return the price in `_REDSTONE_OUTPUT_DECIMALS`\n if (_REDSTONE_INVERT_RATE) {\n // invert the price\n return _REDSTONE_INVERT_PRICE_DIVIDEND / exchangeRate_;\n } else {\n return exchangeRate_ * _REDSTONE_PRICE_SCALER_MULTIPLIER;\n }\n } catch {\n return 0;\n }\n }\n\n /// @notice returns all Redstone oracle related data as utility for easy off-chain use / block explorer in a single view method\n function redstoneOracleData()\n public\n view\n returns (uint256 redstoneExchangeRate_, IRedstoneOracle redstoneOracle_, bool redstoneInvertRate_)\n {\n return (\n address(_REDSTONE_ORACLE) == _REDSTONE_ORACLE_NOT_SET_ADDRESS ? 0 : _getRedstoneExchangeRate(),\n _REDSTONE_ORACLE,\n _REDSTONE_INVERT_RATE\n );\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/redstoneOracleImpl2.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { RedstoneStructs } from \"./structs.sol\";\n\n// @dev Exact same contract as RedstoneOracleImpl, just with all vars, immutables etc. renamed with a \"2\" to avoid\n// conflicts when RedstoneOracleImpl would have to be inherited twice.\n\n/// @title Redstone Oracle implementation\n/// @notice This contract is used to get the exchange rate from a Redstone Oracle\nabstract contract RedstoneOracleImpl2 is OracleError, RedstoneStructs {\n /// @notice Redstone price oracle to check for the exchange rate\n IRedstoneOracle internal immutable _REDSTONE2_ORACLE;\n /// @notice Flag to invert the price or not (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _REDSTONE2_INVERT_RATE;\n\n /// @notice constant value for price scaling to reduce gas usage\n uint256 internal immutable _REDSTONE2_PRICE_SCALER_MULTIPLIER;\n /// @notice constant value for inverting price to reduce gas usage\n uint256 internal immutable _REDSTONE2_INVERT_PRICE_DIVIDEND;\n\n address internal immutable _REDSTONE2_ORACLE_NOT_SET_ADDRESS = 0x000000000000000000000000000000000000dEaD;\n\n /// @notice constructor sets the Redstone oracle data\n constructor(RedstoneOracleData memory oracleData_) {\n if (address(oracleData_.oracle) == address(0) || oracleData_.token0Decimals == 0) {\n revert FluidOracleError(ErrorTypes.RedstoneOracle__InvalidParams);\n }\n\n _REDSTONE2_ORACLE = oracleData_.oracle;\n _REDSTONE2_INVERT_RATE = oracleData_.invertRate;\n\n // for explanation on how to get to scaler multiplier and dividend see `chainlinkOracleImpl.sol`.\n // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n _REDSTONE2_PRICE_SCALER_MULTIPLIER = address(oracleData_.oracle) == _REDSTONE2_ORACLE_NOT_SET_ADDRESS\n ? 1\n : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - oracleData_.token0Decimals);\n _REDSTONE2_INVERT_PRICE_DIVIDEND = address(oracleData_.oracle) == _REDSTONE2_ORACLE_NOT_SET_ADDRESS\n ? 1\n : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + oracleData_.token0Decimals);\n }\n\n /// @dev Get the exchange rate from Redstone oracle\n /// @param rate_ The exchange rate in `_REDSTONE2_OUTPUT_DECIMALS`\n function _getRedstoneExchangeRate2() internal view returns (uint256 rate_) {\n try _REDSTONE2_ORACLE.getExchangeRate() returns (uint256 exchangeRate_) {\n // Return the price in `_REDSTONE2_OUTPUT_DECIMALS`\n if (_REDSTONE2_INVERT_RATE) {\n // invert the price\n return _REDSTONE2_INVERT_PRICE_DIVIDEND / exchangeRate_;\n } else {\n return exchangeRate_ * _REDSTONE2_PRICE_SCALER_MULTIPLIER;\n }\n } catch {\n return 0;\n }\n }\n\n /// @notice returns all Redstone oracle related data as utility for easy off-chain use / block explorer in a single view method\n function redstoneOracleData2()\n public\n view\n returns (uint256 redstoneExchangeRate_, IRedstoneOracle redstoneOracle_, bool redstoneInvertRate_)\n {\n return (\n address(_REDSTONE2_ORACLE) == _REDSTONE2_ORACLE_NOT_SET_ADDRESS ? 0 : _getRedstoneExchangeRate2(),\n _REDSTONE2_ORACLE,\n _REDSTONE2_INVERT_RATE\n );\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/structs.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IChainlinkAggregatorV3 } from \"../interfaces/external/IChainlinkAggregatorV3.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\n\nabstract contract ChainlinkStructs {\n struct ChainlinkFeedData {\n /// @param feed address of Chainlink feed.\n IChainlinkAggregatorV3 feed;\n /// @param invertRate true if rate read from price feed must be inverted.\n bool invertRate;\n /// @param token0Decimals decimals of asset 0. E.g. for a USDC/ETH feed, USDC is token0 and has 6 decimals.\n /// (token1Decimals are available directly via Chainlink `FEED.decimals()`)\n uint256 token0Decimals;\n }\n\n struct ChainlinkConstructorParams {\n /// @param param hops count of hops, used for sanity checks. Must be 1, 2 or 3.\n uint8 hops;\n /// @param feed1 Chainlink feed 1 data. Required.\n ChainlinkFeedData feed1;\n /// @param feed2 Chainlink feed 2 data. Required if hops > 1.\n ChainlinkFeedData feed2;\n /// @param feed3 Chainlink feed 3 data. Required if hops > 2.\n ChainlinkFeedData feed3;\n }\n}\n\nabstract contract RedstoneStructs {\n struct RedstoneOracleData {\n /// @param oracle address of Redstone oracle.\n IRedstoneOracle oracle;\n /// @param invertRate true if rate read from price feed must be inverted.\n bool invertRate;\n /// @param token0Decimals decimals of asset 0. E.g. for a USDC/ETH feed, USDC is token0 and has 6 decimals.\n /// (token1Decimals are available directly via Redstone `Oracle.decimals()`)\n uint256 token0Decimals;\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/uniV3OracleImpl.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { FullMath } from \"../libraries/FullMath.sol\";\nimport { TickMath } from \"../libraries/TickMath.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { IUniswapV3Pool } from \"../interfaces/external/IUniswapV3Pool.sol\";\nimport { Error as OracleError } from \"../error.sol\";\n\n/// @title Uniswap V3 Oracle implementation\n/// @notice This contract is used to get the exchange rate from from a Uniswap V3 Pool,\n/// including logic to check against TWAP max deltas.\n/// @dev Uses 5 secondsAgos[] values and 3 TWAP maxDeltas:\n/// e.g. [240, 60, 15, 1, 0] -> [price240to60, price60to15, price 15to1, currentPrice]\n/// delta checks: price240to60 vs currentPrice, price60to15 vs currentPrice and 15to1 vs currentPrice.\nabstract contract UniV3OracleImpl is OracleError {\n /// @dev Uniswap V3 Pool to check for the exchange rate\n IUniswapV3Pool internal immutable _POOL;\n\n /// @dev Flag to invert the price or not (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n bool internal immutable _UNIV3_INVERT_RATE;\n\n /// @dev Uniswap oracle delta for TWAP1 in 1e2 percent. If uniswap price TWAP1 is out of this delta,\n /// current price fetching reverts. E.g. for delta of TWAP 240 -> 60 vs current price\n uint256 internal immutable _UNI_TWAP1_MAX_DELTA_PERCENT;\n /// @dev Uniswap oracle delta for TWAP2 in 1e2 percent. If uniswap price TWAP2 is out of this delta,\n /// current price fetching reverts. E.g. for delta of TWAP 60 -> 15 vs current price\n uint256 internal immutable _UNI_TWAP2_MAX_DELTA_PERCENT;\n /// @dev Uniswap oracle delta for TWAP3 in 1e2 percent. If uniswap price TWAP3 is out of this delta,\n /// current price fetching reverts. E.g. for delta of TWAP 15 -> 1 vs current price\n uint256 internal immutable _UNI_TWAP3_MAX_DELTA_PERCENT;\n\n /// @dev Uniswap oracle seconds ago for twap, 1. value, e.g. 240\n uint256 internal immutable _UNI_SECONDS_AGO_1;\n /// @dev Uniswap oracle seconds ago for twap, 2. value, e.g. 60\n uint256 internal immutable _UNI_SECONDS_AGO_2;\n /// @dev Uniswap oracle seconds ago for twap, 3. value, e.g. 15\n uint256 internal immutable _UNI_SECONDS_AGO_3;\n /// @dev Uniswap oracle seconds ago for twap, 4. value, e.g. 1\n uint256 internal immutable _UNI_SECONDS_AGO_4;\n /// @dev Uniswap oracle seconds ago for twap, 5. value, e.g. 0\n uint256 internal immutable _UNI_SECONDS_AGO_5;\n\n /// @dev Uniswap TWAP1 interval duration.\n int256 internal immutable _UNI_TWAP1_INTERVAL;\n /// @dev Uniswap TWAP2 interval duration.\n int256 internal immutable _UNI_TWAP2_INTERVAL;\n /// @dev Uniswap TWAP3 interval duration.\n int256 internal immutable _UNI_TWAP3_INTERVAL;\n /// @dev Uniswap TWAP4 interval duration.\n int256 internal immutable _UNI_TWAP4_INTERVAL;\n\n /// @dev stored array lengths to optimize gas\n uint256 internal constant _SECONDS_AGOS_LENGTH = 5;\n uint256 internal constant _TWAP_DELTAS_LENGTH = 3;\n\n /// @dev constant value for price scaling to reduce gas usage\n uint256 internal immutable _UNIV3_PRICE_SCALER_MULTIPLIER;\n /// @dev constant value for inverting price to reduce gas usage\n uint256 internal immutable _UNIV3_INVERT_PRICE_DIVIDEND;\n\n struct UniV3ConstructorParams {\n /// @param pool Uniswap V3 Pool to check for the exchange rate\n IUniswapV3Pool pool;\n /// @param invertRate Flag to invert the Uniswap price or not\n bool invertRate;\n /// @param tWAPMaxDeltaPercents Uniswap oracle delta for TWAP1-2-3 in 1e2 percent\n uint256[_TWAP_DELTAS_LENGTH] tWAPMaxDeltaPercents;\n /// @param secondsAgos Uniswap oracle seconds ago for the 3 TWAP values, from oldest to newest, e.g. [240, 60, 15, 1, 0]\n uint32[_SECONDS_AGOS_LENGTH] secondsAgos;\n }\n\n /// @notice constructor sets the Uniswap V3 `pool_` to check for the exchange rate and the `invertRate_` flag.\n /// E.g. `invertRate_` should be true if for the WETH/USDC pool it's expected that the oracle returns USDC per 1 WETH\n constructor(UniV3ConstructorParams memory params_) {\n if (address(params_.pool) == address(0)) {\n revert FluidOracleError(ErrorTypes.UniV3Oracle__InvalidParams);\n }\n // sanity check that seconds agos values are ordered ascending, e.g. [240, 60, 15, 1, 0]\n if (\n params_.secondsAgos[0] <= params_.secondsAgos[1] ||\n params_.secondsAgos[1] <= params_.secondsAgos[2] ||\n params_.secondsAgos[2] <= params_.secondsAgos[3] ||\n params_.secondsAgos[3] <= params_.secondsAgos[4]\n ) {\n revert FluidOracleError(ErrorTypes.UniV3Oracle__InvalidSecondsAgos);\n }\n // sanity check that deltas are less than 100% and decreasing (as timespan is closer to current price):\n // 1. delta must < 100%\n // all following deltas must be <= than the previous one\n if (\n params_.tWAPMaxDeltaPercents[0] >= OracleUtils.HUNDRED_PERCENT_DELTA_SCALER ||\n params_.tWAPMaxDeltaPercents[1] > params_.tWAPMaxDeltaPercents[0] ||\n params_.tWAPMaxDeltaPercents[2] > params_.tWAPMaxDeltaPercents[1]\n ) {\n revert FluidOracleError(ErrorTypes.UniV3Oracle__InvalidDeltas);\n }\n\n _UNI_SECONDS_AGO_1 = uint256(params_.secondsAgos[0]);\n _UNI_SECONDS_AGO_2 = uint256(params_.secondsAgos[1]);\n _UNI_SECONDS_AGO_3 = uint256(params_.secondsAgos[2]);\n _UNI_SECONDS_AGO_4 = uint256(params_.secondsAgos[3]);\n _UNI_SECONDS_AGO_5 = uint256(params_.secondsAgos[4]);\n\n _UNI_TWAP1_INTERVAL = int256(uint256(params_.secondsAgos[0] - params_.secondsAgos[1]));\n _UNI_TWAP2_INTERVAL = int256(uint256(params_.secondsAgos[1] - params_.secondsAgos[2]));\n _UNI_TWAP3_INTERVAL = int256(uint256(params_.secondsAgos[2] - params_.secondsAgos[3]));\n _UNI_TWAP4_INTERVAL = int256(uint256(params_.secondsAgos[3] - params_.secondsAgos[4]));\n\n _UNI_TWAP1_MAX_DELTA_PERCENT = params_.tWAPMaxDeltaPercents[0]; // e.g. for TWAP 240 -> 60 vs current price\n _UNI_TWAP2_MAX_DELTA_PERCENT = params_.tWAPMaxDeltaPercents[1]; // e.g. for TWAP 60 -> 15 vs current price\n _UNI_TWAP3_MAX_DELTA_PERCENT = params_.tWAPMaxDeltaPercents[2]; // e.g. for TWAP 15 -> 1 vs current price\n\n _POOL = params_.pool;\n _UNIV3_INVERT_RATE = params_.invertRate;\n\n // uniswapV3 returned price is already scaled to token decimals.\n _UNIV3_PRICE_SCALER_MULTIPLIER = 10 ** OracleUtils.RATE_OUTPUT_DECIMALS;\n // uniV3 invert price dividend happens on the already scaled by 1e27 result for price in token1 per 1 token0\n _UNIV3_INVERT_PRICE_DIVIDEND = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS * 2);\n }\n\n /// @dev Get the last exchange rate from the pool's last observed value without any checks\n /// @return exchangeRateUnsafe_ The exchange rate between the underlying asset and the peg asset in `OracleUtils.RATE_OUTPUT_DECIMALS`\n function _getUniV3ExchangeRateUnsafe() internal view returns (uint256 exchangeRateUnsafe_) {\n (uint160 sqrtPriceX96_, , , , , , ) = _POOL.slot0();\n\n exchangeRateUnsafe_ = _UNIV3_INVERT_RATE\n ? _invertUniV3Price(_getPriceFromSqrtPriceX96(sqrtPriceX96_))\n : _getPriceFromSqrtPriceX96(sqrtPriceX96_);\n }\n\n /// @dev Get the last exchange rate from the pool's last observed value, checked against TWAP deviations.\n /// @return exchangeRate_ The exchange rate between the underlying asset and the peg asset in `OracleUtils.RATE_OUTPUT_DECIMALS`\n /// If 0 then the fetching the price failed or a delta was invalid.\n function _getUniV3ExchangeRate() internal view returns (uint256 exchangeRate_) {\n // build calldata bytes in a gas-optimized way without having to build an array / using abi.encode.\n // gas efficient work around for Solidity not supporting immutable non-value types.\n bytes memory data_ = abi.encodePacked(\n hex\"883bdbfd\", // pack function selector\n hex\"0000000000000000000000000000000000000000000000000000000000000020\", // pack start offset of dynamic array\n _SECONDS_AGOS_LENGTH, // pack length of dynamic array\n // pack seconds agos values:\n _UNI_SECONDS_AGO_1,\n _UNI_SECONDS_AGO_2,\n _UNI_SECONDS_AGO_3,\n _UNI_SECONDS_AGO_4,\n _UNI_SECONDS_AGO_5\n );\n\n // get the tickCumulatives from Pool.observe()\n (bool success_, bytes memory result_) = address(_POOL).staticcall(data_);\n\n if (!success_) {\n return 0;\n }\n int56[] memory tickCumulatives_ = abi.decode(result_, (int56[]));\n\n unchecked {\n {\n int56 tickCumulativesDelta_ = (tickCumulatives_[_TWAP_DELTAS_LENGTH + 1] -\n tickCumulatives_[_TWAP_DELTAS_LENGTH]);\n // _UNI_TWAP4_INTERVAL can not be 0 because of constructor sanity checks\n int24 arithmeticMeanTick_ = int24(tickCumulativesDelta_ / _UNI_TWAP4_INTERVAL);\n // Always round to negative infinity, see UniV3 OracleLibrary\n // https://github.com/Uniswap/v3-periphery/blob/697c2474757ea89fec12a4e6db16a574fe259610/contracts/libraries/OracleLibrary.sol#L36\n if (tickCumulativesDelta_ < 0 && (tickCumulativesDelta_ % _UNI_TWAP4_INTERVAL != 0)) {\n arithmeticMeanTick_--;\n }\n\n // get the current uniswap price, which is the last tick cumulatives interval, usually [..., 1, 0]\n exchangeRate_ = _getPriceFromSqrtPriceX96(TickMath.getSqrtRatioAtTick(arithmeticMeanTick_));\n }\n if (_UNIV3_INVERT_RATE) {\n exchangeRate_ = _invertUniV3Price(exchangeRate_);\n }\n\n // Check the latest Uniswap price is within the acceptable delta from each TWAP range\n // TWAP 1 check\n if (\n _isInvalidTWAPDelta(\n exchangeRate_,\n tickCumulatives_[1] - tickCumulatives_[0],\n _UNI_TWAP1_INTERVAL,\n _UNI_TWAP1_MAX_DELTA_PERCENT\n )\n ) {\n return 0;\n }\n\n // TWAP 2 check\n if (\n _isInvalidTWAPDelta(\n exchangeRate_,\n tickCumulatives_[2] - tickCumulatives_[1],\n _UNI_TWAP2_INTERVAL,\n _UNI_TWAP2_MAX_DELTA_PERCENT\n )\n ) {\n return 0;\n }\n\n // TWAP 3 check\n if (\n _isInvalidTWAPDelta(\n exchangeRate_,\n tickCumulatives_[3] - tickCumulatives_[2],\n _UNI_TWAP3_INTERVAL,\n _UNI_TWAP3_MAX_DELTA_PERCENT\n )\n ) {\n return 0;\n }\n }\n }\n\n /// @dev verifies that `exchangeRate_` is within `maxDelta_` for derived price from `tickCumulativesDelta_` and `interval_`.\n /// returns true if delta is invalid\n function _isInvalidTWAPDelta(\n uint256 exchangeRate_,\n int256 tickCumulativesDelta_,\n int256 interval_, // can not be 0 because of constructor sanity checks\n uint256 maxDelta_\n ) internal view returns (bool) {\n unchecked {\n int24 arithmeticMeanTick_ = int24(tickCumulativesDelta_ / interval_);\n // Always round to negative infinity, see UniV3 OracleLibrary\n // https://github.com/Uniswap/v3-periphery/blob/697c2474757ea89fec12a4e6db16a574fe259610/contracts/libraries/OracleLibrary.sol#L36\n if (tickCumulativesDelta_ < 0 && (tickCumulativesDelta_ % interval_ != 0)) {\n arithmeticMeanTick_--;\n }\n\n // Get the price for the interval of the twap\n uint256 price_ = _getPriceFromSqrtPriceX96(TickMath.getSqrtRatioAtTick(arithmeticMeanTick_));\n if (_UNIV3_INVERT_RATE) {\n price_ = _invertUniV3Price(price_);\n }\n // Check that the uniswapPrice is within DELTA of the Uniswap TWAP\n maxDelta_ = (price_ * maxDelta_) / OracleUtils.HUNDRED_PERCENT_DELTA_SCALER;\n if (exchangeRate_ > (price_ + maxDelta_) || exchangeRate_ < (price_ - maxDelta_)) {\n // Uniswap last price is NOT within the delta\n return true;\n }\n }\n return false;\n }\n\n /// @notice returns all UniV3 oracle related data as utility for easy off-chain use / block explorer in a single view method\n function uniV3OracleData()\n public\n view\n returns (\n IUniswapV3Pool uniV3Pool_,\n bool uniV3InvertRate_,\n uint32[] memory uniV3secondsAgos_,\n uint256[] memory uniV3TwapDeltas_,\n uint256 uniV3exchangeRateUnsafe_,\n uint256 uniV3exchangeRate_\n )\n {\n // Get the latest TWAP prices from the Uniswap Oracle for second intervals\n uniV3secondsAgos_ = new uint32[](_SECONDS_AGOS_LENGTH);\n uniV3secondsAgos_[0] = uint32(_UNI_SECONDS_AGO_1);\n uniV3secondsAgos_[1] = uint32(_UNI_SECONDS_AGO_2);\n uniV3secondsAgos_[2] = uint32(_UNI_SECONDS_AGO_3);\n uniV3secondsAgos_[3] = uint32(_UNI_SECONDS_AGO_4);\n uniV3secondsAgos_[4] = uint32(_UNI_SECONDS_AGO_5);\n\n // Check the latest Uniswap price is within the acceptable delta from each TWAP range\n uniV3TwapDeltas_ = new uint256[](_TWAP_DELTAS_LENGTH);\n uniV3TwapDeltas_[0] = _UNI_TWAP1_MAX_DELTA_PERCENT;\n uniV3TwapDeltas_[1] = _UNI_TWAP2_MAX_DELTA_PERCENT;\n uniV3TwapDeltas_[2] = _UNI_TWAP3_MAX_DELTA_PERCENT;\n\n return (\n _POOL,\n _UNIV3_INVERT_RATE,\n uniV3secondsAgos_,\n uniV3TwapDeltas_,\n _getUniV3ExchangeRateUnsafe(),\n _getUniV3ExchangeRate()\n );\n }\n\n /// @dev Get the price from the sqrt price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n /// (see https://blog.uniswap.org/uniswap-v3-math-primer)\n /// @param sqrtPriceX96_ The sqrt price to convert\n function _getPriceFromSqrtPriceX96(uint160 sqrtPriceX96_) private view returns (uint256 priceX96_) {\n return\n FullMath.mulDiv(\n uint256(sqrtPriceX96_) * uint256(sqrtPriceX96_),\n _UNIV3_PRICE_SCALER_MULTIPLIER,\n 1 << 192 // 2^96 * 2\n );\n }\n\n /// @dev Invert the price\n /// @param price_ The price to invert\n /// @return invertedPrice_ The inverted price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n function _invertUniV3Price(uint256 price_) private view returns (uint256 invertedPrice_) {\n return _UNIV3_INVERT_PRICE_DIVIDEND / price_;\n }\n}\n"
|
||
},
|
||
"contracts/oracle/implementations/wstETHOracleImpl.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IWstETH } from \"../interfaces/external/IWstETH.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\n\n/// @title wstETH Oracle Implementation\n/// @notice This contract is used to get the exchange rate between wstETH and stETH\nabstract contract WstETHOracleImpl is OracleError {\n /// @notice constant value for price scaling to reduce gas usage\n uint256 internal immutable _WSTETH_PRICE_SCALER_MULTIPLIER;\n\n /// @notice WSTETH contract, e.g. on mainnet 0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0\n IWstETH internal immutable _WSTETH;\n\n /// @notice constructor sets the wstETH `wstETH_` token address.\n constructor(IWstETH wstETH_) {\n if (address(wstETH_) == address(0)) {\n revert FluidOracleError(ErrorTypes.WstETHOracle__InvalidParams);\n }\n\n _WSTETH = wstETH_;\n\n _WSTETH_PRICE_SCALER_MULTIPLIER = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - 18); // e.g. 1e9\n }\n\n /// @notice Get the exchange rate from wstETH contract\n /// @return rate_ The exchange rate in `WSTETH_OUTPUT_DECIMALS`\n function _getWstETHExchangeRate() internal view returns (uint256 rate_) {\n return _WSTETH.stEthPerToken() * _WSTETH_PRICE_SCALER_MULTIPLIER;\n }\n\n /// @notice returns all wWtETH oracle related data as utility for easy off-chain use / block explorer in a single view method\n function wstETHOracleData() public view returns (uint256 wstETHExchangeRate_, IWstETH wstETH_) {\n return (_getWstETHExchangeRate(), _WSTETH);\n }\n}\n"
|
||
},
|
||
"contracts/oracle/interfaces/external/IChainlinkAggregatorV3.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\n/// from https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\n/// Copyright (c) 2018 SmartContract ChainLink, Ltd.\n\ninterface IChainlinkAggregatorV3 {\n /// @notice represents the number of decimals the aggregator responses represent.\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function latestRoundData()\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n}\n"
|
||
},
|
||
"contracts/oracle/interfaces/external/IRedstoneOracle.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IRedstoneOracle {\n /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset\n // @dev custom Redstone adapter for Instadapp implementation\n function getExchangeRate() external view returns (uint256 exchangeRate_);\n\n /**\n * @notice Returns the number of decimals for the price feed\n * @dev By default, RedStone uses 8 decimals for data feeds\n * @return decimals The number of decimals in the price feed values\n */\n // see https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/on-chain-relayer/contracts/price-feeds/PriceFeedBase.sol#L51C12-L51C20\n function decimals() external view returns (uint8);\n}\n"
|
||
},
|
||
"contracts/oracle/interfaces/external/IUniswapV3Pool.sol": {
|
||
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.21;\n\n/// from https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces.\n/// Copyright (c) 2022 Uniswap Labs\n\n/// @title Pool state that never changes\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\ninterface IUniswapV3PoolImmutables {\n /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\n /// @return The contract address\n function factory() external view returns (address);\n\n /// @notice The first of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token0() external view returns (address);\n\n /// @notice The second of the two tokens of the pool, sorted by address\n /// @return The token contract address\n function token1() external view returns (address);\n\n /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\n /// @return The fee\n function fee() external view returns (uint24);\n\n /// @notice The pool tick spacing\n /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\n /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\n /// This value is an int24 to avoid casting even though it is always positive.\n /// @return The tick spacing\n function tickSpacing() external view returns (int24);\n\n /// @notice The maximum amount of position liquidity that can use any tick in the range\n /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\n /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\n /// @return The max amount of liquidity per tick\n function maxLiquidityPerTick() external view returns (uint128);\n}\n\n/// @title Pool state that is not stored\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\n/// blockchain. The functions here may have variable gas costs.\ninterface IUniswapV3PoolDerivedState {\n /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\n /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\n /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\n /// you must call it with secondsAgos = [3600, 0].\n /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\n /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\n /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\n /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\n /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\n /// timestamp\n function observe(\n uint32[] calldata secondsAgos\n ) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\n\n /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\n /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\n /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\n /// snapshot is taken and the second snapshot is taken.\n /// @param tickLower The lower tick of the range\n /// @param tickUpper The upper tick of the range\n /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\n /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\n /// @return secondsInside The snapshot of seconds per liquidity for the range\n function snapshotCumulativesInside(\n int24 tickLower,\n int24 tickUpper\n ) external view returns (int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside);\n}\n\n/// @title Pool state that can change\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\n/// per transaction\ninterface IUniswapV3PoolState {\n /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\n /// when accessed externally.\n /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\n /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\n /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\n /// boundary.\n /// observationIndex The index of the last oracle observation that was written,\n /// observationCardinality The current maximum number of observations stored in the pool,\n /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\n /// feeProtocol The protocol fee for both tokens of the pool.\n /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\n /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\n /// unlocked Whether the pool is currently locked to reentrancy\n function slot0()\n external\n view\n returns (\n uint160 sqrtPriceX96,\n int24 tick,\n uint16 observationIndex,\n uint16 observationCardinality,\n uint16 observationCardinalityNext,\n uint8 feeProtocol,\n bool unlocked\n );\n\n /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\n /// @dev This value can overflow the uint256\n function feeGrowthGlobal0X128() external view returns (uint256);\n\n /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\n /// @dev This value can overflow the uint256\n function feeGrowthGlobal1X128() external view returns (uint256);\n\n /// @notice The amounts of token0 and token1 that are owed to the protocol\n /// @dev Protocol fees will never exceed uint128 max in either token\n function protocolFees() external view returns (uint128 token0, uint128 token1);\n\n /// @notice The currently in range liquidity available to the pool\n /// @dev This value has no relationship to the total liquidity across all ticks\n function liquidity() external view returns (uint128);\n\n /// @notice Look up information about a specific tick in the pool\n /// @param tick The tick to look up\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\n /// tick upper,\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\n /// a specific position.\n function ticks(\n int24 tick\n )\n external\n view\n returns (\n uint128 liquidityGross,\n int128 liquidityNet,\n uint256 feeGrowthOutside0X128,\n uint256 feeGrowthOutside1X128,\n int56 tickCumulativeOutside,\n uint160 secondsPerLiquidityOutsideX128,\n uint32 secondsOutside,\n bool initialized\n );\n\n /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\n function tickBitmap(int16 wordPosition) external view returns (uint256);\n\n /// @notice Returns the information about a position by the position's key\n /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\n /// @return _liquidity The amount of liquidity in the position,\n /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\n /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\n /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\n /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\n function positions(\n bytes32 key\n )\n external\n view\n returns (\n uint128 _liquidity,\n uint256 feeGrowthInside0LastX128,\n uint256 feeGrowthInside1LastX128,\n uint128 tokensOwed0,\n uint128 tokensOwed1\n );\n\n /// @notice Returns data about a specific observation index\n /// @param index The element of the observations array to fetch\n /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\n /// ago, rather than at a specific index in the array.\n /// @return blockTimestamp The timestamp of the observation,\n /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\n /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\n /// Returns initialized whether the observation has been initialized and the values are safe to use\n function observations(\n uint256 index\n )\n external\n view\n returns (\n uint32 blockTimestamp,\n int56 tickCumulative,\n uint160 secondsPerLiquidityCumulativeX128,\n bool initialized\n );\n}\n\n/// @title The interface for a Uniswap V3 Pool\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\n/// to the ERC20 specification\n/// @dev The pool interface is broken up into many smaller pieces\ninterface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState, IUniswapV3PoolDerivedState {\n\n}\n"
|
||
},
|
||
"contracts/oracle/interfaces/external/IWstETH.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IWstETH {\n /**\n * @notice Get amount of stETH for 1 wstETH\n * @return Amount of stETH for 1 wstETH\n */\n function stEthPerToken() external view returns (uint256);\n\n /**\n * @notice Get amount of wstETH for 1 stETH\n * @return Amount of wstETH for 1 stETH\n */\n function tokensPerStEth() external view returns (uint256);\n}\n"
|
||
},
|
||
"contracts/oracle/interfaces/iFluidOracle.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IFluidOracle {\n /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27\n function getExchangeRate() external view returns (uint256 exchangeRate_);\n}\n"
|
||
},
|
||
"contracts/oracle/libraries/FullMath.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\n/// @dev Modified from the original UniswapV3 library to support v0.8\n/// From: uint256 twos = -denominator & denominator;\n/// To: uint256 twos = (type(uint256).max - denominator + 1) & denominator;\n\n/// @title Contains 512-bit math functions\n/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision\n/// @dev Handles \"phantom overflow\" i.e., allows multiplication and division where an intermediate value overflows 256 bits\nlibrary FullMath {\n /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n /// @param a The multiplicand\n /// @param b The multiplier\n /// @param denominator The divisor\n /// @return result The 256-bit result\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\n function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {\n // 512-bit multiply [prod1 prod0] = a * b\n // Compute the product mod 2**256 and mod 2**256 - 1\n // then use the Chinese Remainder Theorem to reconstruct\n // the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2**256 + prod0\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(a, b, not(0))\n prod0 := mul(a, b)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division\n if (prod1 == 0) {\n require(denominator > 0);\n assembly {\n result := div(prod0, denominator)\n }\n return result;\n }\n\n // Make sure the result is less than 2**256.\n // Also prevents denominator == 0\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0]\n // Compute remainder using mulmod\n uint256 remainder;\n assembly {\n remainder := mulmod(a, b, denominator)\n }\n // Subtract 256 bit number from 512 bit number\n assembly {\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator\n // Compute largest power of two divisor of denominator.\n // Always >= 1.\n /// @dev This line was modified for v0.8.x\n // uint256 twos = -denominator & denominator;\n uint256 twos = (type(uint256).max - denominator + 1) & denominator;\n // Divide denominator by power of two\n assembly {\n denominator := div(denominator, twos)\n }\n\n // Divide [prod1 prod0] by the factors of two\n assembly {\n prod0 := div(prod0, twos)\n }\n // Shift in bits from prod1 into prod0. For this we need\n // to flip `twos` such that it is 2**256 / twos.\n // If twos is zero, then it becomes one\n assembly {\n twos := add(div(sub(0, twos), twos), 1)\n }\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2**256\n // Now that denominator is an odd number, it has an inverse\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\n // Compute the inverse by starting with a seed that is correct\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\n uint256 inv = (3 * denominator) ^ 2;\n // Now use Newton-Raphson iteration to improve the precision.\n // Thanks to Hensel's lifting lemma, this also works in modular\n // arithmetic, doubling the correct bits in each step.\n inv *= 2 - denominator * inv; // inverse mod 2**8\n inv *= 2 - denominator * inv; // inverse mod 2**16\n inv *= 2 - denominator * inv; // inverse mod 2**32\n inv *= 2 - denominator * inv; // inverse mod 2**64\n inv *= 2 - denominator * inv; // inverse mod 2**128\n inv *= 2 - denominator * inv; // inverse mod 2**256\n\n // Because the division is now exact we can divide by multiplying\n // with the modular inverse of denominator. This will give us the\n // correct result modulo 2**256. Since the precoditions guarantee\n // that the outcome is less than 2**256, this is the final result.\n // We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inv;\n return result;\n }\n\n /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n /// @param a The multiplicand\n /// @param b The multiplier\n /// @param denominator The divisor\n /// @return result The 256-bit result\n function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {\n result = mulDiv(a, b, denominator);\n if (mulmod(a, b, denominator) > 0) {\n require(result < type(uint256).max);\n result++;\n }\n }\n}\n"
|
||
},
|
||
"contracts/oracle/libraries/oracleUtils.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title Oracle utils library\n/// @notice implements common utility methods for Fluid Oracles\nlibrary OracleUtils {\n /// @dev The scaler for max delta point math (100%)\n uint256 internal constant HUNDRED_PERCENT_DELTA_SCALER = 10_000;\n /// @dev output precision of rates\n uint256 internal constant RATE_OUTPUT_DECIMALS = 27;\n\n /// @dev checks if `mainSourceRate_` is within a `maxDeltaPercent_` of `checkSourceRate_`. Returns true if so.\n function isRateOutsideDelta(\n uint256 mainSourceRate_,\n uint256 checkSourceRate_,\n uint256 maxDeltaPercent_\n ) internal pure returns (bool) {\n uint256 offset_ = (checkSourceRate_ * maxDeltaPercent_) / HUNDRED_PERCENT_DELTA_SCALER;\n return (mainSourceRate_ > (checkSourceRate_ + offset_) || mainSourceRate_ < (checkSourceRate_ - offset_));\n }\n}\n"
|
||
},
|
||
"contracts/oracle/libraries/TickMath.sol": {
|
||
"content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.21;\n\n/// @dev Modified from the original UniswapV3 library to support v0.8\n/// From: require(absTick <= uint256(MAX_TICK), 'T');\n/// To: require(absTick <= uint256(int(MAX_TICK)), 'T');\n\n/// @title Math library for computing sqrt prices from ticks and vice versa\n/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports\n/// prices between 2**-128 and 2**128\nlibrary TickMath {\n /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\n int24 internal constant MIN_TICK = -887272;\n /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\n int24 internal constant MAX_TICK = -MIN_TICK;\n\n /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\n uint160 internal constant MIN_SQRT_RATIO = 4295128739;\n /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\n uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;\n\n /// @notice Calculates sqrt(1.0001^tick) * 2^96\n /// @dev Throws if |tick| > max tick\n /// @param tick The input tick for the above formula\n /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\n /// at the given tick\n function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {\n uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n /// @dev This line was modified for v0.8.x\n // require(absTick <= uint256(MAX_TICK), 'T');\n require(absTick <= uint256(int(MAX_TICK)), \"T\");\n\n uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;\n if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\n if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\n if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\n if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\n if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\n if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\n if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\n if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\n if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\n if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\n if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\n if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\n if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\n if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\n if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\n if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\n if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\n if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\n if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\n\n if (tick > 0) ratio = type(uint256).max / ratio;\n\n // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\n // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\n // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\n sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n }\n\n /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\n /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\n /// ever return.\n /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\n /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\n function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\n // second inequality must be < because the price can never reach the price at the max tick\n require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, \"R\");\n uint256 ratio = uint256(sqrtPriceX96) << 32;\n\n uint256 r = ratio;\n uint256 msb = 0;\n\n assembly {\n let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\n msb := or(msb, f)\n r := shr(f, r)\n }\n assembly {\n let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\n msb := or(msb, f)\n r := shr(f, r)\n }\n assembly {\n let f := shl(5, gt(r, 0xFFFFFFFF))\n msb := or(msb, f)\n r := shr(f, r)\n }\n assembly {\n let f := shl(4, gt(r, 0xFFFF))\n msb := or(msb, f)\n r := shr(f, r)\n }\n assembly {\n let f := shl(3, gt(r, 0xFF))\n msb := or(msb, f)\n r := shr(f, r)\n }\n assembly {\n let f := shl(2, gt(r, 0xF))\n msb := or(msb, f)\n r := shr(f, r)\n }\n assembly {\n let f := shl(1, gt(r, 0x3))\n msb := or(msb, f)\n r := shr(f, r)\n }\n assembly {\n let f := gt(r, 0x1)\n msb := or(msb, f)\n }\n\n if (msb >= 128) r = ratio >> (msb - 127);\n else r = ratio << (127 - msb);\n\n int256 log_2 = (int256(msb) - 128) << 64;\n\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(63, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(62, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(61, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(60, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(59, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(58, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(57, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(56, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(55, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(54, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(53, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(52, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(51, f))\n r := shr(f, r)\n }\n assembly {\n r := shr(127, mul(r, r))\n let f := shr(128, r)\n log_2 := or(log_2, shl(50, f))\n }\n\n int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number\n\n int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);\n int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);\n\n tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;\n }\n}\n"
|
||
},
|
||
"contracts/oracle/oracles/uniV3CheckCLRSOracle.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { FluidOracle } from \"../fluidOracle.sol\";\nimport { FallbackOracleImpl } from \"../implementations/fallbackOracleImpl.sol\";\nimport { UniV3OracleImpl } from \"../implementations/uniV3OracleImpl.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\n\n/// @title UniswapV3 checked against Chainlink / Redstone Oracle. Either one reported as exchange rate.\n/// @notice Gets the exchange rate between the underlying asset and the peg asset by using:\n/// the price from a UniV3 pool (compared against 3 TWAPs) and (optionally) comparing it against a Chainlink\n/// or Redstone price (one of Chainlink or Redstone being the main source and the other one the fallback source).\n/// Alternatively it can also use Chainlink / Redstone as main price and use UniV3 as check price.\n/// @dev The process for getting the aggregate oracle price is:\n/// 1. Fetch the UniV3 TWAPS, the latest interval is used as the current price\n/// 2. Verify this price is within an acceptable DELTA from the Uniswap TWAPS e.g.:\n/// a. 240 to 60s\n/// b. 60 to 15s\n/// c. 15 to 1s (last block)\n/// d. 1 to 0s (current)\n/// 3. (unless UniV3 only mode): Verify this price is within an acceptable DELTA from the Chainlink / Redstone Oracle\n/// 4. If it passes all checks, return the price. Otherwise use fallbacks, usually to Chainlink. In extreme edge-cases revert.\n/// @dev For UniV3 with check mode, if fetching the check price fails, the UniV3 rate is used directly.\ncontract UniV3CheckCLRSOracle is FluidOracle, UniV3OracleImpl, FallbackOracleImpl {\n /// @dev Rate check oracle delta percent in 1e2 percent. If current uniswap price is out of this delta,\n /// current price fetching reverts.\n uint256 internal immutable _RATE_CHECK_MAX_DELTA_PERCENT;\n\n /// @dev which oracle to use as final rate source:\n /// - 1 = UniV3 ONLY (no check),\n /// - 2 = UniV3 with Chainlink / Redstone check\n /// - 3 = Chainlink / Redstone with UniV3 used as check.\n uint8 internal immutable _RATE_SOURCE;\n\n struct UniV3CheckCLRSConstructorParams {\n /// @param uniV3Params UniV3Oracle constructor params struct.\n UniV3ConstructorParams uniV3Params;\n /// @param chainlinkParams ChainlinkOracle constructor params struct for UniV3CheckCLRSOracle.\n ChainlinkConstructorParams chainlinkParams;\n /// @param redstoneOracle Redstone Oracle data for UniV3CheckCLRSOracle. (address can be set to zero address if using Chainlink only)\n RedstoneOracleData redstoneOracle;\n /// @param rateSource which oracle to use as final rate source for UniV3CheckCLRSOracle:\n /// - 1 = UniV3 ONLY (no check),\n /// - 2 = UniV3 with Chainlink / Redstone check\n /// - 3 = Chainlink / Redstone with UniV3 used as check.\n uint8 rateSource;\n /// @param fallbackMainSource which oracle to use as CL/RS main source for UniV3CheckCLRSOracle: see FallbackOracleImpl constructor `mainSource_`\n uint8 fallbackMainSource;\n /// @param rateCheckMaxDeltaPercent Rate check oracle delta in 1e2 percent for UniV3CheckCLRSOracle\n uint256 rateCheckMaxDeltaPercent;\n }\n\n constructor(\n UniV3CheckCLRSConstructorParams memory params_\n )\n UniV3OracleImpl(params_.uniV3Params)\n FallbackOracleImpl(params_.fallbackMainSource, params_.chainlinkParams, params_.redstoneOracle)\n {\n if (\n params_.rateSource < 1 ||\n params_.rateSource > 3 ||\n params_.rateCheckMaxDeltaPercent > OracleUtils.HUNDRED_PERCENT_DELTA_SCALER ||\n // Chainlink only Oracle with UniV3 check. Delta would be ignored so revert this type of Oracle setup.\n (params_.fallbackMainSource == 1 && params_.rateSource == 3)\n ) {\n revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__InvalidParams);\n }\n\n _RATE_CHECK_MAX_DELTA_PERCENT = params_.rateCheckMaxDeltaPercent;\n _RATE_SOURCE = params_.rateSource;\n }\n\n /// @inheritdoc FluidOracle\n function getExchangeRate() public view virtual override returns (uint256 exchangeRate_) {\n if (_RATE_SOURCE == 1) {\n // uniswap is the only main source without check:\n // 1. get uniV3 rate.\n // 2. If that fails (outside delta range) -> revert (no other Oracle configured).\n exchangeRate_ = _getUniV3ExchangeRate();\n\n if (exchangeRate_ == 0) {\n // fetching UniV3 failed or invalid delta -> revert\n revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__ExchangeRateZero);\n }\n\n return exchangeRate_;\n }\n\n uint256 checkRate_;\n bool fallback_;\n if (_RATE_SOURCE == 2) {\n // uniswap is main source, with Chainlink / Redstone as check\n // 1. get uniV3 rate\n\n // case uniV3 rate fails (outside delta range):\n // 2. get Chainlink rate. -> if successful, use Chainlink as result\n // 3. if Chainlink fails too, get Redstone -> if successful, use Redstone as result\n // 4. if Redstone fails too, revert\n\n // case if uniV3 rate is ok\n // 2. get Chainlink or Redstone rate for check (one is configured as main check source, other one is fallback source)\n // -> if both fail to fetch, use uniV3 rate directly.\n // 3. check the delta for uniV3 rate against the check soure rate. -> if ok, return uniV3 rate\n // 4. if delta check fails, check delta against the fallback check source. -> if ok, return uniV3 rate\n // 5. if delta check fails for both sources, return Chainlink price\n\n exchangeRate_ = _getUniV3ExchangeRate();\n\n if (exchangeRate_ == 0) {\n // uniV3 failed or invalid delta -> use (Chainlink with Redstone as fallback)\n exchangeRate_ = _getChainlinkOrRedstoneAsFallback();\n if (exchangeRate_ == 0) {\n // Chainlink / Redstone failed too -> revert\n revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__ExchangeRateZero);\n }\n return exchangeRate_;\n }\n\n (checkRate_, fallback_) = _getRateWithFallback();\n if (checkRate_ == 0) {\n // check price source failed to fetch -> directly use uniV3 TWAP checked price\n // Note uniV3 price fetching was successful, would have been caught otherwise above.\n return exchangeRate_;\n }\n } else {\n // Chainlink / Redstone is main source, with uniV3 as check.\n // 1. get Chainlink / Redstone rate (one is configured as main source, other one is fallback source)\n\n // case when both Chainlink & Redstone fail:\n // 2. get uniV3 rate. if successful, use uniV3 rate. otherwise, revert (all oracles failed).\n\n // case when Chainlink / Redstone fetch is successful:\n // 2. get uniV3 rate for check.\n // 3. if uniV3 rate fails to fetch (outside delta), use Chainlink / Redstone directly (skip check).\n // 4. if uniV3 rate is ok, check the delta for Chainlink / Redstone rate against uniV3 rate.\n // -> if ok, return Chainlink / Redstone (main) rate\n // 5. if delta check fails, check delta against the fallback main source.\n // -> if ok, return fallback main rate\n // 6. if delta check fails for both sources, return Chainlink price.\n\n (exchangeRate_, fallback_) = _getRateWithFallback();\n checkRate_ = _getUniV3ExchangeRate();\n\n if (exchangeRate_ == 0) {\n if (checkRate_ == 0) {\n // all oracles failed, revert\n revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__ExchangeRateZero);\n }\n\n // Both Chainlink & Redstone failed -> directly use uniV3 TWAP checked price\n // Note uniV3 price fetching was successful, would have been caught otherwise above.\n return checkRate_;\n }\n\n if (checkRate_ == 0) {\n // uniV3 failed -> skip check against Uniswap price.\n\n return exchangeRate_;\n }\n }\n\n if (OracleUtils.isRateOutsideDelta(exchangeRate_, checkRate_, _RATE_CHECK_MAX_DELTA_PERCENT)) {\n if (fallback_) {\n // fallback already used, no other rate available to check.\n\n // if price is chainlink price -> return it.\n if (_FALLBACK_ORACLE_MAIN_SOURCE == 3) {\n // redstone with Chainlink as fallback\n return _RATE_SOURCE == 2 ? checkRate_ : exchangeRate_; // if rate source is 2, Chainlink rate is in checkRate_\n }\n\n // if price is redstone price -> revert\n revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__InvalidPrice);\n }\n\n if (_FALLBACK_ORACLE_MAIN_SOURCE == 1) {\n // 1 = only chainlink and UniV3 is configured and delta check failed. no fallback available.\n if (_RATE_SOURCE == 2) {\n // case where uniV3 is main source with only Chainlink as check rate Oracle configured.\n // delta check failed -> return Chainlink price (instead of uniV3 price).\n return checkRate_;\n }\n\n // here: if (_FALLBACK_ORACLE_MAIN_SOURCE == 1 && _RATE_SOURCE == 3)\n // rate source is 3: Chainlink as main, uniV3 as delta. delta check failed.\n // this Oracle type would basically be a more expensive Chainlink-only Oracle because the delta check against UniV3 is ignored.\n // this setup is reverted in constructor, but in any case returning Chainlink price here even though this code should never be reached.\n return exchangeRate_; // exchangeRate_ here is chainlink price\n }\n\n // fallback not done yet -> check against fallback price.\n // So if originally Chainlink was fetched and delta failed, check against Redstone.\n // if originally Redstone was fetched and delta failed, check against Chainlink.\n if (_FALLBACK_ORACLE_MAIN_SOURCE == 2) {\n // 2 = Chainlink with Redstone Fallback. delta check against Chainlink failed. try against Redstone.\n uint256 redstoneRate_ = _getRedstoneExchangeRate();\n uint256 chainlinkRate_;\n if (_RATE_SOURCE == 2) {\n // uniV3 main source. -> update checkRate_ with Redstone price\n chainlinkRate_ = checkRate_;\n checkRate_ = redstoneRate_;\n } else {\n // uniV3 is check source. -> update exchangeRate_ with Redstone price\n chainlinkRate_ = exchangeRate_;\n exchangeRate_ = redstoneRate_;\n }\n\n if (redstoneRate_ == 0) {\n // fetching Redstone failed. So delta UniV3 <> Chainlink failed, fetching Redstone as backup failed.\n // -> return chainlink price (for both cases when Chainlink is main and when UniV3 is the main source).\n return chainlinkRate_;\n }\n\n if (OracleUtils.isRateOutsideDelta(exchangeRate_, checkRate_, _RATE_CHECK_MAX_DELTA_PERCENT)) {\n // delta check against Redstone failed too. return Chainlink price\n return chainlinkRate_;\n }\n\n // delta check against Redstone passed. if uniV3 main source -> return uniV3, else return Redstone.\n // exchangeRate_ is already set correctly for this.\n } else {\n // 3 = Redstone with Chainlink Fallback. delta check against Redstone failed. try against Chainlink.\n uint256 chainlinkRate_ = _getChainlinkExchangeRate();\n if (chainlinkRate_ == 0) {\n // fetching Chainlink failed. So delta UniV3 <> Redstone failed, fetching Chainlink as backup check failed.\n // -> revert.\n revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__InvalidPrice);\n }\n\n if (_RATE_SOURCE == 3) {\n // uniV3 is check source. -> update exchangeRate_ with Chainlink price.\n // Optimization: in this case we can directly return chainlink price, because if delta check between\n // Chainlink (new main source) and uniV3 (check source) fails, we anyway return Chainlink price still.\n return chainlinkRate_;\n }\n\n // uniV3 main source. -> update checkRate_ with Chainlink price and compare delta again\n checkRate_ = chainlinkRate_;\n\n if (OracleUtils.isRateOutsideDelta(exchangeRate_, checkRate_, _RATE_CHECK_MAX_DELTA_PERCENT)) {\n // delta check against Chainlink failed too. case here can only be where uniV3 would have been\n // main source and Chainlink check source. -> return Chainlink as price instead of uniV3\n return checkRate_;\n }\n\n // delta check against Chainlink passed. if uniV3 main source -> return uniV3, else return Chainlink.\n // exchangeRate_ is already set correctly for this.\n }\n }\n }\n\n /// @notice returns all oracle related data as utility for easy off-chain / block explorer use in a single view method\n function uniV3CheckOracleData()\n public\n view\n returns (uint256 rateCheckMaxDelta_, uint256 rateSource_, uint256 fallbackMainSource_)\n {\n return (_RATE_CHECK_MAX_DELTA_PERCENT, _RATE_SOURCE, _FALLBACK_ORACLE_MAIN_SOURCE);\n }\n}\n"
|
||
},
|
||
"contracts/oracle/oracles/wstETHCLRS2UniV3CheckCLRSOracle.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { FluidOracle } from \"../fluidOracle.sol\";\nimport { UniV3CheckCLRSOracle } from \"./uniV3CheckCLRSOracle.sol\";\nimport { WstETHOracleImpl } from \"../implementations/wstETHOracleImpl.sol\";\nimport { FallbackOracleImpl2 } from \"../implementations/fallbackOracleImpl2.sol\";\nimport { IWstETH } from \"../interfaces/external/IWstETH.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\n\n// @dev uses FallbackOracleImpl2 to avoid conflicts with already used ChainlinkOracleImpl, RedstoneOracleImpl and\n// FallbackOracleImpl in UniV3CheckCLRSOracle.\n\n/// @title wstETHCLRSOracle combined with a uniV3CheckCLRSOracle.\n/// @notice Gets the exchange rate between the underlying asset and the peg asset by using:\n/// 1. wstETH Oracle price in combination with rate from Chainlink price feeds (or Redstone as fallback).\n/// combining those two into one rate resulting in wstETH <> someToken\n/// 2. result from 1. combined with a uniV3CheckCLRSOracle to get from someToken <> someToken2\n/// e.g. when going from wstETH to USDC:\n/// 1. wstETH -> stETH wstETH Oracle, stETH -> ETH Chainlink feed.\n/// 2, ETH -> USDC via UniV3 ETH <> USDC pool checked against ETH -> USDC Chainlink feed.\ncontract WstETHCLRS2UniV3CheckCLRSOracle is FluidOracle, WstETHOracleImpl, FallbackOracleImpl2, UniV3CheckCLRSOracle {\n struct WstETHCLRS2ConstructorParams {\n /// @param wstETH address of the wstETH contract\n IWstETH wstETH;\n /// @param fallbackMainSource which oracle to use as main source for wstETH <> CLRS: 1 = Chainlink, 2 = Redstone (other one is fallback).\n uint8 fallbackMainSource;\n /// @param chainlinkParams chainlink Oracle constructor params struct for wstETH <> CLRS.\n ChainlinkConstructorParams chainlinkParams;\n /// @param redstoneOracle Redstone Oracle data for wstETH <> CLRS. (address can be set to zero address if using Chainlink only)\n RedstoneOracleData redstoneOracle;\n }\n\n /// @notice constructs a WstETHCLRS2UniV3CheckCLRSOracle with all inherited contracts\n /// @param wstETHCLRS2Params_ WstETHCLRS2ConstructorParams for wstETH <> CLRS Token2 conversion\n /// @param uniV3CheckCLRSParams_ UniV3CheckCLRSOracle constructor params\n constructor(\n WstETHCLRS2ConstructorParams memory wstETHCLRS2Params_,\n UniV3CheckCLRSConstructorParams memory uniV3CheckCLRSParams_\n )\n WstETHOracleImpl(wstETHCLRS2Params_.wstETH)\n FallbackOracleImpl2(\n wstETHCLRS2Params_.fallbackMainSource,\n wstETHCLRS2Params_.chainlinkParams,\n wstETHCLRS2Params_.redstoneOracle\n )\n UniV3CheckCLRSOracle(uniV3CheckCLRSParams_)\n {}\n\n /// @inheritdoc FluidOracle\n function getExchangeRate() public view override(FluidOracle, UniV3CheckCLRSOracle) returns (uint256 exchangeRate_) {\n // 1. get CLRS Oracle rate for stETH <> CLRS feed. uses FallbackOracleImpl2\n (exchangeRate_, ) = _getRateWithFallback2();\n if (exchangeRate_ == 0) {\n // revert if fetched exchange rate is 0\n revert FluidOracleError(ErrorTypes.WstETHCLRS2UniV3CheckCLRSOracle__ExchangeRateZero);\n }\n\n // 2. combine CLRS feed price with wstETH price to have wstETH <> stETH <> SomeToken fully converted\n exchangeRate_ = (_getWstETHExchangeRate() * exchangeRate_) / (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n\n // 3. get rate from UniV3Check Oracle (likely uniV3 / Chainlink checked against for delta). This always returns\n // a price if some rate is valid, with multiple fallbacks. Can not return 0. Combine this rate with existing.\n // (super.getExchangeRate() returns UniV3CheckCLRSOracle rate, no other inherited contract has this.)\n exchangeRate_ = (super.getExchangeRate() * exchangeRate_) / (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n }\n\n /// @notice which oracle to use as main source for stETH <> CLRS: 1 = Chainlink, 2 = Redstone (other one is fallback).\n function FALLBACK_ORACLE2_MAIN_SOURCE() public view returns (uint8) {\n return _FALLBACK_ORACLE2_MAIN_SOURCE;\n }\n}\n"
|
||
},
|
||
"contracts/periphery/resolvers/lending/iLendingResolver.sol": {
|
||
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\nimport { IAllowanceTransfer } from \"../../../protocols/lending/interfaces/permit2/iAllowanceTransfer.sol\";\nimport { IFluidLendingFactory } from \"../../../protocols/lending/interfaces/iLendingFactory.sol\";\nimport { IFluidLendingRewardsRateModel } from \"../../../protocols/lending/interfaces/iLendingRewardsRateModel.sol\";\nimport { IFToken } from \"../../../protocols/lending/interfaces/iFToken.sol\";\nimport { Structs } from \"./structs.sol\";\nimport { IFluidLiquidityResolver } from \"../../../periphery/resolvers/liquidity/iLiquidityResolver.sol\";\n\ninterface IFluidLendingResolver {\n /// @notice returns the lending factory address\n function LENDING_FACTORY() external view returns (IFluidLendingFactory);\n\n /// @notice returns the liquidity resolver address\n function LIQUIDITY_RESOLVER() external view returns (IFluidLiquidityResolver);\n\n /// @notice returns all fToken types at the `LENDING_FACTORY`\n function getAllFTokenTypes() external view returns (string[] memory);\n\n /// @notice returns all created fTokens at the `LENDING_FACTORY`\n function getAllFTokens() external view returns (address[] memory);\n\n /// @notice reads if a certain `auth_` address is an allowed auth or not. Owner is auth by default.\n function isLendingFactoryAuth(address auth_) external view returns (bool);\n\n /// @notice reads if a certain `deployer_` address is an allowed deployer or not. Owner is deployer by default.\n function isLendingFactoryDeployer(address deployer_) external view returns (bool);\n\n /// @notice computes deterministic token address for `asset_` for a lending protocol\n /// @param asset_ address of the asset\n /// @param fTokenType_ type of fToken:\n /// - if underlying asset supports EIP-2612, the fToken should be type `EIP2612Deposits`\n /// - otherwise it should use `Permit2Deposits`\n /// - if it's the native token, it should use `NativeUnderlying`\n /// - could be more types available, check `fTokenTypes()`\n /// @return token_ detemrinistic address of the computed token\n function computeFToken(address asset_, string calldata fTokenType_) external view returns (address);\n\n /// @notice gets all public details for a certain `fToken_`, such as\n /// fToken type, name, symbol, decimals, underlying asset, total amounts, convertTo values, rewards.\n /// Note it also returns whether the fToken supports deposits / mints via EIP-2612, but it is not a 100% guarantee!\n /// To make sure, check for the underlying if it supports EIP-2612 manually.\n /// @param fToken_ the fToken to get the details for\n /// @return fTokenDetails_ retrieved FTokenDetails struct\n function getFTokenDetails(IFToken fToken_) external view returns (Structs.FTokenDetails memory fTokenDetails_);\n\n /// @notice returns config, rewards and exchange prices data of an fToken.\n /// @param fToken_ the fToken to get the data for\n /// @return liquidity_ address of the Liquidity contract.\n /// @return lendingFactory_ address of the Lending factory contract.\n /// @return lendingRewardsRateModel_ address of the rewards rate model contract. changeable by LendingFactory auths.\n /// @return permit2_ address of the Permit2 contract used for deposits / mint with signature\n /// @return rebalancer_ address of the rebalancer allowed to execute `rebalance()`\n /// @return rewardsActive_ true if rewards are currently active\n /// @return liquidityBalance_ current Liquidity supply balance of `address(this)` for the underyling asset\n /// @return liquidityExchangePrice_ (updated) exchange price for the underlying assset in the liquidity protocol (without rewards)\n /// @return tokenExchangePrice_ (updated) exchange price between fToken and the underlying assset (with rewards)\n function getFTokenInternalData(\n IFToken fToken_\n )\n external\n view\n returns (\n IFluidLiquidity liquidity_,\n IFluidLendingFactory lendingFactory_,\n IFluidLendingRewardsRateModel lendingRewardsRateModel_,\n IAllowanceTransfer permit2_,\n address rebalancer_,\n bool rewardsActive_,\n uint256 liquidityBalance_,\n uint256 liquidityExchangePrice_,\n uint256 tokenExchangePrice_\n );\n\n /// @notice gets all public details for all itokens, such as\n /// fToken type, name, symbol, decimals, underlying asset, total amounts, convertTo values, rewards\n function getFTokensEntireData() external view returns (Structs.FTokenDetails[] memory);\n\n /// @notice gets all public details for all itokens, such as\n /// fToken type, name, symbol, decimals, underlying asset, total amounts, convertTo values, rewards\n /// and user position for each token\n function getUserPositions(address user_) external view returns (Structs.FTokenDetailsUserPosition[] memory);\n\n /// @notice gets rewards related data: the `rewardsRateModel_` contract and the current `rewardsRate_` for the `fToken_`\n function getFTokenRewards(\n IFToken fToken_\n ) external view returns (IFluidLendingRewardsRateModel rewardsRateModel_, uint256 rewardsRate_);\n\n /// @notice gets rewards rate model config constants\n function getFTokenRewardsRateModelConfig(\n IFToken fToken_\n )\n external\n view\n returns (\n uint256 duration_,\n uint256 startTime_,\n uint256 endTime_,\n uint256 startTvl_,\n uint256 maxRate_,\n uint256 rewardAmount_,\n address initiator_\n );\n\n /// @notice gets a `user_` position for an `fToken_`.\n /// @return userPosition user position struct\n function getUserPosition(\n IFToken fToken_,\n address user_\n ) external view returns (Structs.UserPosition memory userPosition);\n\n /// @notice gets `fToken_` preview amounts for `assets_` or `shares_`.\n /// @return previewDeposit_ preview for deposit of `assets_`\n /// @return previewMint_ preview for mint of `shares_`\n /// @return previewWithdraw_ preview for withdraw of `assets_`\n /// @return previewRedeem_ preview for redeem of `shares_`\n function getPreviews(\n IFToken fToken_,\n uint256 assets_,\n uint256 shares_\n )\n external\n view\n returns (uint256 previewDeposit_, uint256 previewMint_, uint256 previewWithdraw_, uint256 previewRedeem_);\n}\n"
|
||
},
|
||
"contracts/periphery/resolvers/lending/main.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20Permit } from \"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { LiquidityCalcs } from \"../../../libraries/liquidityCalcs.sol\";\nimport { IFluidLendingFactory } from \"../../../protocols/lending/interfaces/iLendingFactory.sol\";\nimport { IFluidLendingRewardsRateModel } from \"../../../protocols/lending/interfaces/iLendingRewardsRateModel.sol\";\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\nimport { IAllowanceTransfer } from \"../../../protocols/lending/interfaces/permit2/iAllowanceTransfer.sol\";\nimport { IFToken, IFTokenNativeUnderlying } from \"../../../protocols/lending/interfaces/iFToken.sol\";\nimport { IFluidLiquidityResolver } from \"../../../periphery/resolvers/liquidity/iLiquidityResolver.sol\";\nimport { Structs as LiquidityStructs } from \"../../../periphery/resolvers/liquidity/structs.sol\";\nimport { IFluidLendingResolver } from \"./iLendingResolver.sol\";\nimport { Structs } from \"./structs.sol\";\n\n/// @notice Fluid Lending protocol (fTokens) resolver\n/// Implements various view-only methods to give easy access to Lending protocol data.\ncontract FluidLendingResolver is IFluidLendingResolver, Structs {\n /// @dev address that is mapped to the chain native token\n address internal constant _NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @inheritdoc IFluidLendingResolver\n IFluidLendingFactory public immutable LENDING_FACTORY;\n\n /// @inheritdoc IFluidLendingResolver\n IFluidLiquidityResolver public immutable LIQUIDITY_RESOLVER;\n\n /// @notice thrown if an input param address is zero\n error FluidLendingResolver__AddressZero();\n\n /// @notice constructor sets the immutable `LENDING_FACTORY` address\n constructor(IFluidLendingFactory lendingFactory_, IFluidLiquidityResolver liquidityResolver_) {\n if (address(lendingFactory_) == address(0) || address(liquidityResolver_) == address(0)) {\n revert FluidLendingResolver__AddressZero();\n }\n LENDING_FACTORY = lendingFactory_;\n LIQUIDITY_RESOLVER = liquidityResolver_;\n }\n\n /// @inheritdoc IFluidLendingResolver\n function isLendingFactoryAuth(address auth_) external view returns (bool) {\n return LENDING_FACTORY.isAuth(auth_);\n }\n\n /// @inheritdoc IFluidLendingResolver\n function isLendingFactoryDeployer(address deployer_) external view returns (bool) {\n return LENDING_FACTORY.isDeployer(deployer_);\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getAllFTokenTypes() public view returns (string[] memory) {\n return LENDING_FACTORY.fTokenTypes();\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getAllFTokens() public view returns (address[] memory) {\n return LENDING_FACTORY.allTokens();\n }\n\n /// @inheritdoc IFluidLendingResolver\n function computeFToken(address asset_, string calldata fTokenType_) external view returns (address) {\n return LENDING_FACTORY.computeToken(asset_, fTokenType_);\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getFTokenDetails(IFToken fToken_) public view returns (FTokenDetails memory fTokenDetails_) {\n address underlying_ = fToken_.asset();\n\n bool isNativeUnderlying_ = false;\n try IFTokenNativeUnderlying(address(fToken_)).NATIVE_TOKEN_ADDRESS() {\n // if NATIVE_TOKEN_ADDRESS is defined, fTokenType must be NativeUnderlying.\n isNativeUnderlying_ = true;\n } catch {}\n\n bool supportsEIP2612Deposits_ = false;\n try IERC20Permit(underlying_).DOMAIN_SEPARATOR() {\n // if DOMAIN_SEPARATOR is defined, we assume underlying supports EIP2612. Not a 100% guarantee\n supportsEIP2612Deposits_ = true;\n } catch {}\n\n (, uint256 rewardsRate_) = getFTokenRewards(fToken_);\n (\n LiquidityStructs.UserSupplyData memory userSupplyData_,\n LiquidityStructs.OverallTokenData memory overallTokenData_\n ) = LIQUIDITY_RESOLVER.getUserSupplyData(\n address(fToken_),\n isNativeUnderlying_ ? _NATIVE_TOKEN_ADDRESS : underlying_\n );\n\n uint256 totalAssets_ = fToken_.totalAssets();\n\n fTokenDetails_ = FTokenDetails(\n address(fToken_),\n supportsEIP2612Deposits_,\n isNativeUnderlying_,\n fToken_.name(),\n fToken_.symbol(),\n fToken_.decimals(),\n underlying_,\n totalAssets_,\n fToken_.totalSupply(),\n fToken_.convertToShares(10 ** fToken_.decimals()), // example convertToShares for 10 ** decimals\n fToken_.convertToAssets(10 ** fToken_.decimals()), // example convertToAssets for 10 ** decimals\n rewardsRate_,\n overallTokenData_.supplyRate,\n int256(userSupplyData_.supply) - int256(totalAssets_), // rebalanceDifference\n userSupplyData_\n );\n\n return fTokenDetails_;\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getFTokenInternalData(\n IFToken fToken_\n )\n public\n view\n returns (\n IFluidLiquidity liquidity_,\n IFluidLendingFactory lendingFactory_,\n IFluidLendingRewardsRateModel lendingRewardsRateModel_,\n IAllowanceTransfer permit2_,\n address rebalancer_,\n bool rewardsActive_,\n uint256 liquidityBalance_,\n uint256 liquidityExchangePrice_,\n uint256 tokenExchangePrice_\n )\n {\n return fToken_.getData();\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getFTokensEntireData() public view returns (FTokenDetails[] memory) {\n address[] memory allTokens = getAllFTokens();\n FTokenDetails[] memory fTokenDetailsArr_ = new FTokenDetails[](allTokens.length);\n for (uint256 i = 0; i < allTokens.length; ) {\n fTokenDetailsArr_[i] = getFTokenDetails(IFToken(allTokens[i]));\n unchecked {\n i++;\n }\n }\n return fTokenDetailsArr_;\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getUserPositions(address user_) external view returns (FTokenDetailsUserPosition[] memory) {\n FTokenDetails[] memory fTokensEntireData_ = getFTokensEntireData();\n FTokenDetailsUserPosition[] memory userPositionArr_ = new FTokenDetailsUserPosition[](\n fTokensEntireData_.length\n );\n for (uint256 i = 0; i < fTokensEntireData_.length; ) {\n userPositionArr_[i].fTokenDetails = fTokensEntireData_[i];\n userPositionArr_[i].userPosition = getUserPosition(IFToken(fTokensEntireData_[i].tokenAddress), user_);\n unchecked {\n i++;\n }\n }\n return userPositionArr_;\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getFTokenRewards(\n IFToken fToken_\n ) public view returns (IFluidLendingRewardsRateModel rewardsRateModel_, uint256 rewardsRate_) {\n bool rewardsActive_;\n (, , rewardsRateModel_, , , rewardsActive_, , , ) = fToken_.getData();\n\n if (rewardsActive_) {\n (rewardsRate_, , ) = rewardsRateModel_.getRate(fToken_.totalAssets());\n }\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getFTokenRewardsRateModelConfig(\n IFToken fToken_\n )\n public\n view\n returns (\n uint256 duration_,\n uint256 startTime_,\n uint256 endTime_,\n uint256 startTvl_,\n uint256 maxRate_,\n uint256 rewardAmount_,\n address initiator_\n )\n {\n IFluidLendingRewardsRateModel rewardsRateModel_;\n (, , rewardsRateModel_, , , , , , ) = fToken_.getData();\n\n if (address(rewardsRateModel_) != address(0)) {\n (\n duration_,\n startTime_,\n endTime_,\n startTvl_,\n maxRate_,\n rewardAmount_,\n initiator_\n ) = rewardsRateModel_.getConfig();\n }\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getUserPosition(IFToken fToken_, address user_) public view returns (UserPosition memory userPosition) {\n IERC20 underlying_ = IERC20(fToken_.asset());\n\n userPosition.fTokenShares = fToken_.balanceOf(user_);\n userPosition.underlyingAssets = fToken_.convertToAssets(userPosition.fTokenShares);\n userPosition.underlyingBalance = underlying_.balanceOf(user_);\n userPosition.allowance = underlying_.allowance(user_, address(fToken_));\n }\n\n /// @inheritdoc IFluidLendingResolver\n function getPreviews(\n IFToken fToken_,\n uint256 assets_,\n uint256 shares_\n )\n public\n view\n returns (uint256 previewDeposit_, uint256 previewMint_, uint256 previewWithdraw_, uint256 previewRedeem_)\n {\n previewDeposit_ = fToken_.previewDeposit(assets_);\n previewMint_ = fToken_.previewMint(shares_);\n previewWithdraw_ = fToken_.previewWithdraw(assets_);\n previewRedeem_ = fToken_.previewRedeem(shares_);\n }\n}\n"
|
||
},
|
||
"contracts/periphery/resolvers/lending/structs.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLendingFactory } from \"../../../protocols/lending/interfaces/iLendingFactory.sol\";\nimport { Structs as FluidLiquidityResolverStructs } from \"../liquidity/structs.sol\";\n\nabstract contract Structs {\n struct FTokenDetails {\n address tokenAddress;\n bool eip2612Deposits;\n bool isNativeUnderlying;\n string name;\n string symbol;\n uint256 decimals;\n address asset;\n uint256 totalAssets;\n uint256 totalSupply;\n uint256 convertToShares;\n uint256 convertToAssets;\n // additional yield from rewards, if active\n uint256 rewardsRate;\n // yield at Liquidity\n uint256 supplyRate;\n // difference between fToken assets & actual deposit at Liquidity. (supplyAtLiquidity - totalAssets).\n // if negative, rewards must be funded to guarantee withdrawal is possible for all users. This happens\n // by executing rebalance().\n int256 rebalanceDifference;\n // liquidity related data such as supply amount, limits, expansion etc.\n FluidLiquidityResolverStructs.UserSupplyData liquidityUserSupplyData;\n }\n\n struct UserPosition {\n uint256 fTokenShares;\n uint256 underlyingAssets;\n uint256 underlyingBalance;\n uint256 allowance;\n }\n\n struct FTokenDetailsUserPosition {\n FTokenDetails fTokenDetails;\n UserPosition userPosition;\n }\n}\n"
|
||
},
|
||
"contracts/periphery/resolvers/liquidity/iLiquidityResolver.sol": {
|
||
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { Structs as LiquidityStructs } from \"../../../periphery/resolvers/liquidity/structs.sol\";\n\ninterface IFluidLiquidityResolver {\n /// @notice gets the `revenueAmount_` for a `token_`.\n function getRevenue(address token_) external view returns (uint256 revenueAmount_);\n\n /// @notice address of contract that gets sent the revenue. Configurable by governance\n function getRevenueCollector() external view returns (address);\n\n /// @notice Liquidity contract paused status: status = 1 -> normal. status = 2 -> paused.\n function getStatus() external view returns (uint256);\n\n /// @notice checks if `auth_` is an allowed auth on Liquidity.\n /// Auths can set most config values. E.g. contracts that automate certain flows like e.g. adding a new fToken.\n /// Governance can add/remove auths. Governance is auth by default.\n function isAuth(address auth_) external view returns (uint256);\n\n /// @notice checks if `guardian_` is an allowed Guardian on Liquidity.\n /// Guardians can pause lower class users.\n /// Governance can add/remove guardians. Governance is guardian by default.\n function isGuardian(address guardian_) external view returns (uint256);\n\n /// @notice gets user class for `user_`. Class defines which protocols can be paused by guardians.\n /// Currently there are 2 classes: 0 can be paused by guardians. 1 cannot be paused by guardians.\n /// New protocols are added as class 0 and will be upgraded to 1 over time.\n function getUserClass(address user_) external view returns (uint256);\n\n /// @notice gets exchangePricesAndConfig packed uint256 storage slot for `token_`.\n function getExchangePricesAndConfig(address token_) external view returns (uint256);\n\n /// @notice gets rateConfig packed uint256 storage slot for `token_`.\n function getRateConfig(address token_) external view returns (uint256);\n\n /// @notice gets totalAmounts packed uint256 storage slot for `token_`.\n function getTotalAmounts(address token_) external view returns (uint256);\n\n /// @notice gets userSupply data packed uint256 storage slot for `user_` and `token_`.\n function getUserSupply(address user_, address token_) external view returns (uint256);\n\n /// @notice gets userBorrow data packed uint256 storage slot for `user_` and `token_`.\n function getUserBorrow(address user_, address token_) external view returns (uint256);\n\n /// @notice returns all `listedTokens_` at the Liquidity contract. Once configured, a token can never be removed.\n function listedTokens() external view returns (address[] memory listedTokens_);\n\n /// @notice get the Rate config data `rateData_` for a `token_` compiled from the packed uint256 rateConfig storage slot\n function getTokenRateData(address token_) external view returns (LiquidityStructs.RateData memory rateData_);\n\n /// @notice get the Rate config datas `rateDatas_` for multiple `tokens_` compiled from the packed uint256 rateConfig storage slot\n function getTokensRateData(\n address[] calldata tokens_\n ) external view returns (LiquidityStructs.RateData[] memory rateDatas_);\n\n /// @notice returns general data for `token_` such as rates, exchange prices, utilization, fee, total amounts etc.\n function getOverallTokenData(\n address token_\n ) external view returns (LiquidityStructs.OverallTokenData memory overallTokenData_);\n\n /// @notice returns general data for multiple `tokens_` such as rates, exchange prices, utilization, fee, total amounts etc.\n function getOverallTokensData(\n address[] calldata tokens_\n ) external view returns (LiquidityStructs.OverallTokenData[] memory overallTokensData_);\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n function getUserSupplyData(\n address user_,\n address token_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData memory userSupplyData_,\n LiquidityStructs.OverallTokenData memory overallTokenData_\n );\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n function getUserMultipleSupplyData(\n address user_,\n address[] calldata tokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n LiquidityStructs.OverallTokenData[] memory overallTokensData_\n );\n\n /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n function getUserBorrowData(\n address user_,\n address token_\n )\n external\n view\n returns (\n LiquidityStructs.UserBorrowData memory userBorrowData_,\n LiquidityStructs.OverallTokenData memory overallTokenData_\n );\n\n /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n function getUserMultipleBorrowData(\n address user_,\n address[] calldata tokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n LiquidityStructs.OverallTokenData[] memory overallTokensData_\n );\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `supplyTokens_`\n /// and returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `borrowTokens_`\n function getUserMultipleBorrowSupplyData(\n address user_,\n address[] calldata supplyTokens_,\n address[] calldata borrowTokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n LiquidityStructs.OverallTokenData[] memory overallSupplyTokensData_,\n LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n LiquidityStructs.OverallTokenData[] memory overallBorrowTokensData_\n );\n}\n"
|
||
},
|
||
"contracts/periphery/resolvers/liquidity/structs.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Structs as AdminModuleStructs } from \"../../../liquidity/adminModule/structs.sol\";\n\nabstract contract Structs {\n struct RateData {\n uint256 version;\n AdminModuleStructs.RateDataV1Params rateDataV1;\n AdminModuleStructs.RateDataV2Params rateDataV2;\n }\n\n struct OverallTokenData {\n uint256 borrowRate;\n uint256 supplyRate;\n uint256 fee; // revenue fee\n uint256 lastStoredUtilization;\n uint256 storageUpdateThreshold;\n uint256 lastUpdateTimestamp;\n uint256 supplyExchangePrice;\n uint256 borrowExchangePrice;\n uint256 supplyRawInterest;\n uint256 supplyInterestFree;\n uint256 borrowRawInterest;\n uint256 borrowInterestFree;\n uint256 totalSupply;\n uint256 totalBorrow;\n uint256 revenue;\n RateData rateData;\n }\n\n // amounts are always in normal (for withInterest already multiplied with exchange price)\n struct UserSupplyData {\n bool modeWithInterest; // true if mode = with interest, false = without interest\n uint256 supply; // user supply amount\n // the withdrawal limit (e.g. if 10% is the limit, and 100M is supplied, it would be 90M)\n uint256 withdrawalLimit;\n uint256 lastUpdateTimestamp;\n uint256 expandPercent; // withdrawal limit expand percent in 1e2\n uint256 expandDuration; // withdrawal limit expand duration in seconds\n uint256 baseWithdrawalLimit;\n // the current actual max withdrawable amount (e.g. if 10% is the limit, and 100M is supplied, it would be 10M)\n uint256 withdrawableUntilLimit;\n uint256 withdrawable; // actual currently withdrawable amount (supply - withdrawal Limit) & considering balance\n }\n\n // amounts are always in normal (for withInterest already multiplied with exchange price)\n struct UserBorrowData {\n bool modeWithInterest; // true if mode = with interest, false = without interest\n uint256 borrow; // user borrow amount\n uint256 borrowLimit;\n uint256 lastUpdateTimestamp;\n uint256 expandPercent;\n uint256 expandDuration;\n uint256 baseBorrowLimit;\n uint256 maxBorrowLimit;\n uint256 borrowableUntilLimit;\n uint256 borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance\n }\n}\n"
|
||
},
|
||
"contracts/periphery/resolvers/stakingRewards/main.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20Permit } from \"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IFluidLendingResolver } from \"../lending/iLendingResolver.sol\";\nimport { Structs as FluidLendingResolverStructs } from \"../lending/structs.sol\";\nimport { IFluidLendingStakingRewards } from \"../../../protocols/lending/interfaces/iStakingRewards.sol\";\nimport { Structs } from \"./structs.sol\";\n\n\n/// @notice Fluid Lending protocol Staking Rewards (for fTokens) resolver\n/// Implements various view-only methods to give easy access to Lending protocol staked fToken rewards data.\ncontract FluidStakingRewardsResolver is Structs {\n IFluidLendingResolver immutable public LENDING_RESOLVER;\n\n /// @notice thrown if an input param address is zero\n error FluidStakingRewardsResolver__AddressZero();\n\n constructor(address lendingResolver_) {\n if(lendingResolver_ == address(0)){\n revert FluidStakingRewardsResolver__AddressZero();\n }\n LENDING_RESOLVER = IFluidLendingResolver(lendingResolver_);\n }\n\n function getFTokenStakingRewardsEntireData(address reward_) public view returns (FTokenStakingRewardsDetails memory r_) {\n // if address is 0 then data will be returned as 0\n if (reward_ != address(0)) {\n IFluidLendingStakingRewards rewardContract_ = IFluidLendingStakingRewards(reward_);\n \n r_.rewardPerToken = rewardContract_.rewardPerToken();\n r_.getRewardForDuration = rewardContract_.getRewardForDuration();\n r_.totalSupply = rewardContract_.totalSupply();\n r_.periodFinish = rewardContract_.periodFinish();\n r_.rewardRate = rewardContract_.rewardRate();\n r_.rewardsDuration = rewardContract_.rewardsDuration();\n r_.rewardsToken = address(rewardContract_.rewardsToken());\n r_.fToken = address(rewardContract_.stakingToken());\n }\n }\n\n function getFTokensStakingRewardsEntireData(address[] memory rewards_) public view returns (FTokenStakingRewardsDetails[] memory r_) {\n r_ = new FTokenStakingRewardsDetails[](rewards_.length);\n for (uint i = 0; i < rewards_.length; i++) {\n r_[i] = getFTokenStakingRewardsEntireData(rewards_[i]);\n }\n }\n\n function getUserRewardsData(\n address user_,\n address reward_,\n FluidLendingResolverStructs.FTokenDetails memory fTokenDetails_\n ) public view returns (UserRewardDetails memory u_) {\n if (reward_ != address(0)) {\n IFluidLendingStakingRewards rewardContract_ = IFluidLendingStakingRewards(reward_);\n \n u_.earned = rewardContract_.earned(user_);\n u_.fTokenShares = rewardContract_.balanceOf(user_);\n u_.underlyingAssets = (u_.fTokenShares * fTokenDetails_.convertToAssets) / (10**fTokenDetails_.decimals);\n u_.ftokenAllowance = IERC20(fTokenDetails_.tokenAddress).allowance(user_, reward_);\n }\n }\n\n function getUserAllRewardsData(\n address user_,\n address[] memory rewards_,\n FluidLendingResolverStructs.FTokenDetails[] memory fTokensDetails_\n ) public view returns (UserRewardDetails[] memory u_) {\n u_ = new UserRewardDetails[](rewards_.length);\n for (uint i = 0; i < rewards_.length; i++) {\n u_[i] = getUserRewardsData(user_, rewards_[i], fTokensDetails_[i]);\n }\n }\n\n struct underlyingTokenToRewardsMap {\n address underlyingToken;\n address rewardContract;\n }\n\n function getUserPositions(\n address user_,\n underlyingTokenToRewardsMap[] memory rewardsMap_\n ) public view returns (UserFTokenRewardsEntireData[] memory u_) {\n FluidLendingResolverStructs.FTokenDetailsUserPosition[] memory e_ = LENDING_RESOLVER.getUserPositions(user_);\n uint length_ = e_.length;\n u_ = new UserFTokenRewardsEntireData[](length_);\n\n address rewardToken_;\n for (uint i = 0; i < length_; i++) {\n u_[i].fTokenDetails = e_[i].fTokenDetails;\n u_[i].userPosition = e_[i].userPosition;\n for (uint j = 0; j < rewardsMap_.length; j++) {\n if (u_[i].fTokenDetails.asset == rewardsMap_[j].underlyingToken) {\n rewardToken_ = rewardsMap_[j].rewardContract;\n break;\n }\n }\n u_[i].fTokenRewardsDetails = getFTokenStakingRewardsEntireData(rewardToken_);\n u_[i].userRewardsDetails = getUserRewardsData(user_, rewardToken_, u_[i].fTokenDetails);\n rewardToken_ = address(0);\n }\n }\n\n\n}\n"
|
||
},
|
||
"contracts/periphery/resolvers/stakingRewards/structs.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Structs as FluidLendingResolverStructs } from \"../lending/structs.sol\";\n\nabstract contract Structs {\n struct FTokenStakingRewardsDetails {\n uint rewardPerToken; // how much rewards have distributed per token since start\n uint getRewardForDuration; // total rewards being distributed\n uint totalSupply; // total fToken deposited\n uint periodFinish; // when rewards will get over\n uint rewardRate; // total rewards / duration\n uint rewardsDuration; // how long rewards are for since start to end\n address rewardsToken; // which token are we distributing as rewards\n address fToken; // which token are we distributing as rewards\n }\n\n struct UserRewardDetails {\n uint earned;\n uint fTokenShares; // user fToken balance deposited\n uint underlyingAssets; // user fToken balance converted into underlying token\n uint ftokenAllowance; // allowance of fToken to rewards contract\n }\n\n struct UserFTokenRewardsEntireData {\n FluidLendingResolverStructs.FTokenDetails fTokenDetails;\n FluidLendingResolverStructs.UserPosition userPosition;\n FTokenStakingRewardsDetails fTokenRewardsDetails;\n UserRewardDetails userRewardsDetails;\n }\n}\n"
|
||
},
|
||
"contracts/protocols/lending/error.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Error {\n error FluidLendingError(uint256 errorId_);\n}\n"
|
||
},
|
||
"contracts/protocols/lending/errorTypes.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | fToken | \n |__________________________________*/\n\n /// @notice thrown when a deposit amount is too small to increase BigMath stored balance in Liquidity.\n /// precision of BigMath is 1e12, so if token holds 120_000_000_000 USDC, min amount to make a difference would be 0.1 USDC.\n /// i.e. user would send a very small deposit which mints no shares -> revert\n uint256 internal constant fToken__DepositInsignificant = 20001;\n\n /// @notice thrown when minimum output amount is not reached, e.g. for minimum shares minted (deposit) or\n /// minimum assets received (redeem)\n uint256 internal constant fToken__MinAmountOut = 20002;\n\n /// @notice thrown when maximum amount is surpassed, e.g. for maximum shares burned (withdraw) or\n /// maximum assets input (mint)\n uint256 internal constant fToken__MaxAmount = 20003;\n\n /// @notice thrown when invalid params are sent to a method, e.g. zero address\n uint256 internal constant fToken__InvalidParams = 20004;\n\n /// @notice thrown when an unauthorized caller is trying to execute an auth-protected method\n uint256 internal constant fToken__Unauthorized = 20005;\n\n /// @notice thrown when a with permit / signature method is called from msg.sender that is the owner.\n /// Should call the method without permit instead if msg.sender is the owner.\n uint256 internal constant fToken__PermitFromOwnerCall = 20006;\n\n /// @notice thrown when a reentrancy is detected.\n uint256 internal constant fToken__Reentrancy = 20007;\n\n /// @notice thrown when _tokenExchangePrice overflows type(uint64).max\n uint256 internal constant fToken__ExchangePriceOverflow = 20008;\n\n /// @notice thrown when msg.sender is not rebalancer\n uint256 internal constant fToken__NotRebalancer = 20009;\n\n /// @notice thrown when rebalance is called with msg.value > 0 for non NativeUnderlying fToken\n uint256 internal constant fToken__NotNativeUnderlying = 20010;\n\n /// @notice thrown when the received new liquidity exchange price is of unexpected value (< than the old one)\n uint256 internal constant fToken__LiquidityExchangePriceUnexpected = 20011;\n\n /***********************************|\n | fToken Native Underlying | \n |__________________________________*/\n\n /// @notice thrown when native deposit is called but sent along `msg.value` does not cover the deposit amount\n uint256 internal constant fTokenNativeUnderlying__TransferInsufficient = 21001;\n\n /// @notice thrown when a liquidity callback is called for a native token operation\n uint256 internal constant fTokenNativeUnderlying__UnexpectedLiquidityCallback = 21002;\n\n /***********************************|\n | Lending Factory | \n |__________________________________*/\n\n /// @notice thrown when a method is called with invalid params\n uint256 internal constant LendingFactory__InvalidParams = 22001;\n\n /// @notice thrown when the provided input param address is zero\n uint256 internal constant LendingFactory__ZeroAddress = 22002;\n\n /// @notice thrown when the token already exists\n uint256 internal constant LendingFactory__TokenExists = 22003;\n\n /// @notice thrown when the fToken has not yet been configured at Liquidity\n uint256 internal constant LendingFactory__LiquidityNotConfigured = 22004;\n\n /// @notice thrown when an unauthorized caller is trying to execute an auth-protected method\n uint256 internal constant LendingFactory__Unauthorized = 22005;\n\n /***********************************|\n | Lending Rewards Rate Model | \n |__________________________________*/\n\n /// @notice thrown when invalid params are given as input\n uint256 internal constant LendingRewardsRateModel__InvalidParams = 23001;\n\n /// @notice thrown when calculated rewards rate is exceeding the maximum rate\n uint256 internal constant LendingRewardsRateModel__MaxRate = 23002;\n\n /// @notice thrown when start is called by any other address other than initiator\n uint256 internal constant LendingRewardsRateModel__NotTheInitiator = 23003;\n\n /// @notice thrown when start is called after the rewards are already started\n uint256 internal constant LendingRewardsRateModel__AlreadyStarted = 23004;\n\n /// @notice thrown when the provided input param address is zero\n uint256 internal constant LendingRewardsRateModel__ZeroAddress = 23005;\n}\n"
|
||
},
|
||
"contracts/protocols/lending/fToken/events.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLendingRewardsRateModel } from \"../interfaces/iLendingRewardsRateModel.sol\";\n\nabstract contract Events {\n /// @notice emitted whenever admin updates rewards rate model\n event LogUpdateRewards(IFluidLendingRewardsRateModel indexed rewardsRateModel);\n\n /// @notice emitted whenever rebalance is executed to fund difference between Liquidity deposit and totalAssets()\n /// as rewards through the rebalancer.\n event LogRebalance(uint256 assets);\n\n /// @notice emitted whenever exchange rates are updated\n event LogUpdateRates(uint256 tokenExchangePrice, uint256 liquidityExchangePrice);\n\n /// @notice emitted whenever funds for a certain `token` are rescued to Liquidity\n event LogRescueFunds(address indexed token);\n\n /// @notice emitted whenever rebalancer address is updated\n event LogUpdateRebalancer(address indexed rebalancer);\n}\n"
|
||
},
|
||
"contracts/protocols/lending/fToken/main.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ERC20, IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { FixedPointMathLib } from \"solmate/src/utils/FixedPointMathLib.sol\";\nimport { IERC20Permit } from \"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { IAllowanceTransfer } from \"../interfaces/permit2/iAllowanceTransfer.sol\";\nimport { IFluidLendingRewardsRateModel } from \"../interfaces/iLendingRewardsRateModel.sol\";\nimport { IFluidLendingFactory } from \"../interfaces/iLendingFactory.sol\";\nimport { IFToken, IFTokenAdmin } from \"../interfaces/iFToken.sol\";\nimport { LiquidityCalcs } from \"../../../libraries/liquidityCalcs.sol\";\nimport { BigMathMinified } from \"../../../libraries/bigMathMinified.sol\";\nimport { LiquiditySlotsLink } from \"../../../libraries/liquiditySlotsLink.sol\";\nimport { SafeTransfer } from \"../../../libraries/safeTransfer.sol\";\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\nimport { Variables } from \"./variables.sol\";\nimport { Events } from \"./events.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error } from \"../error.sol\";\n\n/// @dev ReentrancyGuard based on OpenZeppelin implementation.\n/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/security/ReentrancyGuard.sol\nabstract contract ReentrancyGuard is Error, Variables {\n uint8 internal constant REENTRANCY_NOT_ENTERED = 1;\n uint8 internal constant REENTRANCY_ENTERED = 2;\n\n constructor() {\n _status = REENTRANCY_NOT_ENTERED;\n }\n\n /// @dev checks that no reentrancy occurs, reverts if so. Calling the method in the modifier reduces\n /// bytecode size as modifiers are inlined into bytecode\n function _checkReentrancy() internal {\n // On the first call to nonReentrant, _status will be NOT_ENTERED\n if (_status != REENTRANCY_NOT_ENTERED) {\n revert FluidLendingError(ErrorTypes.fToken__Reentrancy);\n }\n\n // Any calls to nonReentrant after this point will fail\n _status = REENTRANCY_ENTERED;\n }\n\n /// @dev Prevents a contract from calling itself, directly or indirectly.\n /// See OpenZeppelin implementation for more info\n modifier nonReentrant() {\n _checkReentrancy();\n\n _;\n\n // storing original value triggers a refund (see https://eips.ethereum.org/EIPS/eip-2200)\n _status = REENTRANCY_NOT_ENTERED;\n }\n}\n\n/// @dev internal methods for fToken contracts\nabstract contract fTokenCore is Error, IERC4626, IFToken, Variables, Events, ReentrancyGuard {\n using FixedPointMathLib for uint256;\n\n /// @dev Gets current (updated) Liquidity supply exchange price for the underyling asset\n function _getLiquidityExchangePrice() internal view returns (uint256 supplyExchangePrice_) {\n (supplyExchangePrice_, ) = LiquidityCalcs.calcExchangePrices(\n LIQUIDITY.readFromStorage(LIQUIDITY_EXCHANGE_PRICES_SLOT)\n );\n }\n\n /// @dev Gets current Liquidity supply balance of `address(this)` for the underyling asset\n function _getLiquidityBalance() internal view returns (uint256 balance_) {\n // extract user supply amount\n uint256 userSupplyRaw_ = BigMathMinified.fromBigNumber(\n (LIQUIDITY.readFromStorage(LIQUIDITY_USER_SUPPLY_SLOT) >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) &\n LiquidityCalcs.X64,\n LiquidityCalcs.DEFAULT_EXPONENT_SIZE,\n LiquidityCalcs.DEFAULT_EXPONENT_MASK\n );\n\n unchecked {\n // can not overflow as userSupplyRaw_ can be maximally type(int128).max, liquidity exchange price type(uint64).max\n return (userSupplyRaw_ * _getLiquidityExchangePrice()) / EXCHANGE_PRICES_PRECISION;\n }\n }\n\n /// @dev Gets current Liquidity underlying token balance\n function _getLiquidityUnderlyingBalance() internal view virtual returns (uint256) {\n return ASSET.balanceOf(address(LIQUIDITY));\n }\n\n /// @dev Gets current withdrawable amount at Liquidity `withdrawalLimit_` (withdrawal limit or balance).\n function _getLiquidityWithdrawable() internal view returns (uint256 withdrawalLimit_) {\n uint256 userSupplyData_ = LIQUIDITY.readFromStorage(LIQUIDITY_USER_SUPPLY_SLOT);\n uint256 userSupply_ = BigMathMinified.fromBigNumber(\n (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & LiquidityCalcs.X64,\n LiquidityCalcs.DEFAULT_EXPONENT_SIZE,\n LiquidityCalcs.DEFAULT_EXPONENT_MASK\n );\n withdrawalLimit_ = LiquidityCalcs.calcWithdrawalLimitBeforeOperate(userSupplyData_, userSupply_);\n\n // convert raw amounts to normal amounts\n unchecked {\n // can not overflow as userSupply_ can be maximally type(int128).max\n // and withdrawalLimit is smaller than userSupply_\n uint256 liquidityExchangePrice_ = _getLiquidityExchangePrice();\n withdrawalLimit_ = (withdrawalLimit_ * liquidityExchangePrice_) / EXCHANGE_PRICES_PRECISION;\n userSupply_ = (userSupply_ * liquidityExchangePrice_) / EXCHANGE_PRICES_PRECISION;\n }\n\n withdrawalLimit_ = userSupply_ > withdrawalLimit_ ? userSupply_ - withdrawalLimit_ : 0;\n\n uint256 balanceAtLiquidity_ = _getLiquidityUnderlyingBalance();\n\n return balanceAtLiquidity_ > withdrawalLimit_ ? withdrawalLimit_ : balanceAtLiquidity_;\n }\n\n /// @dev Calculates new token exchange price based on the current liquidity exchange price `newLiquidityExchangePrice_` and rewards rate.\n /// @param newLiquidityExchangePrice_ new (current) liquidity exchange price\n function _calculateNewTokenExchangePrice(\n uint256 newLiquidityExchangePrice_\n ) internal view returns (uint256 newTokenExchangePrice_, bool rewardsEnded_) {\n uint256 oldTokenExchangePrice_ = _tokenExchangePrice;\n uint256 oldLiquidityExchangePrice_ = _liquidityExchangePrice;\n\n if (newLiquidityExchangePrice_ < oldLiquidityExchangePrice_) {\n // liquidity exchange price should only ever increase. If not, something went wrong and avoid\n // proceeding with unknown outcome.\n revert FluidLendingError(ErrorTypes.fToken__LiquidityExchangePriceUnexpected);\n }\n\n uint256 totalReturnInPercent_; // rewardsRateInPercent + liquidityReturnInPercent\n if (_rewardsActive) {\n {\n // get rewards rate per year\n // only trigger call to rewardsRateModel if rewards are actually active to save gas\n uint256 rewardsRate_;\n uint256 rewardsStartTime_;\n (rewardsRate_, rewardsEnded_, rewardsStartTime_) = _rewardsRateModel.getRate(\n // use old tokenExchangeRate to calculate the total assets input for the rewards rate\n (oldTokenExchangePrice_ * totalSupply()) / EXCHANGE_PRICES_PRECISION\n );\n\n if (rewardsRate_ > MAX_REWARDS_RATE || rewardsEnded_) {\n // rewardsRate is capped, if it is bigger > MAX_REWARDS_RATE, then the rewardsRateModel\n // is configured wrongly (which should not be possible). Setting rewards to 0 in that case here.\n rewardsRate_ = 0;\n }\n\n uint256 lastUpdateTimestamp_ = _lastUpdateTimestamp;\n if (lastUpdateTimestamp_ < rewardsStartTime_) {\n // if last update was before the rewards started, make sure rewards actually only accrue\n // from the actual rewards start time, not from the last update timestamp to avoid overpayment.\n lastUpdateTimestamp_ = rewardsStartTime_;\n\n // Note: overpayment for block.timestamp being > rewards end time does not happen because\n // rewardsRate_ is forced 0 then.\n }\n\n // calculate rewards return in percent: (rewards_rate * time passed) / seconds_in_a_year.\n unchecked {\n // rewardsRate * timeElapsed / SECONDS_PER_YEAR.\n // no safe checks needed here because timeElapsed can not underflow,\n // rewardsRate is in 1e12 at max value being MAX_REWARDS_RATE = 25e12\n // max value would be 25e12 * 8589934591 / 31536000 (with buffers) = 6.8e15\n totalReturnInPercent_ =\n (rewardsRate_ * (block.timestamp - lastUpdateTimestamp_)) /\n SECONDS_PER_YEAR;\n }\n }\n }\n\n unchecked {\n // calculate liquidityReturnInPercent: (newLiquidityExchangePrice_ - oldLiquidityExchangePrice_) / oldLiquidityExchangePrice_.\n // and add it to totalReturnInPercent_ that already holds rewardsRateInPercent_.\n // max value (in absolute extreme unrealistic case) would be: 6.8e15 + (((max uint64 - 1e12) * 1e12) / 1e12) = 1.845e19\n // oldLiquidityExchangePrice_ can not be 0, minimal value is 1e12. subtraction can not underflow because new exchange price\n // can only be >= oldLiquidityExchangePrice_.\n totalReturnInPercent_ +=\n ((newLiquidityExchangePrice_ - oldLiquidityExchangePrice_) * 1e14) /\n oldLiquidityExchangePrice_;\n }\n\n // newTokenExchangePrice_ = oldTokenExchangePrice_ + oldTokenExchangePrice_ * totalReturnInPercent_\n newTokenExchangePrice_ = oldTokenExchangePrice_ + ((oldTokenExchangePrice_ * totalReturnInPercent_) / 1e14); // divided by 100% (1e14)\n }\n\n /// @dev calculates new exchange prices, updates values in storage and returns new tokenExchangePrice (with reward rates)\n function _updateRates(\n uint256 liquidityExchangePrice_,\n bool forceUpdateStorage_\n ) internal returns (uint256 tokenExchangePrice_) {\n bool rewardsEnded_;\n (tokenExchangePrice_, rewardsEnded_) = _calculateNewTokenExchangePrice(liquidityExchangePrice_);\n if (_rewardsActive || forceUpdateStorage_) {\n // Solidity will NOT cause a revert if values are too big to fit max uint type size. Explicitly check before\n // writing to storage. Also see https://github.com/ethereum/solidity/issues/10195.\n if (tokenExchangePrice_ > type(uint64).max) {\n revert FluidLendingError(ErrorTypes.fToken__ExchangePriceOverflow);\n }\n\n _tokenExchangePrice = uint64(tokenExchangePrice_);\n _liquidityExchangePrice = uint64(liquidityExchangePrice_);\n _lastUpdateTimestamp = uint40(block.timestamp);\n\n emit LogUpdateRates(tokenExchangePrice_, liquidityExchangePrice_);\n }\n\n if (rewardsEnded_) {\n // set rewardsActive flag to false to save gas for all future exchange prices calculations,\n // without having to explicitly require setting `updateRewards` to address zero.\n // Note that it would be fine that even the current tx does not update exchange prices in storage,\n // because if rewardsEnded_ is true, rewardsRate_ must be 0, so the only yield is from LIQUIDITY.\n // But to be extra safe, writing to storage in that one case too before setting _rewardsActive to false.\n _rewardsActive = false;\n }\n\n return tokenExchangePrice_;\n }\n\n /// @dev splits a bytes signature `sig` into `v`, `r`, `s`.\n /// Taken from https://docs.soliditylang.org/en/v0.8.17/solidity-by-example.html\n function _splitSignature(bytes memory sig) internal pure returns (uint8 v, bytes32 r, bytes32 s) {\n require(sig.length == 65);\n\n assembly {\n // first 32 bytes, after the length prefix.\n r := mload(add(sig, 32))\n // second 32 bytes.\n s := mload(add(sig, 64))\n // final byte (first byte of the next 32 bytes).\n v := byte(0, mload(add(sig, 96)))\n }\n\n return (v, r, s);\n }\n\n /// @dev Deposit `assets_` amount of tokens to Liquidity\n /// @param assets_ The amount of tokens to deposit\n /// @param liquidityCallbackData_ callback data passed to Liquidity for `liquidityCallback`\n /// @return exchangePrice_ liquidity exchange price for token\n function _depositToLiquidity(\n uint256 assets_,\n bytes memory liquidityCallbackData_\n ) internal virtual returns (uint256 exchangePrice_) {\n // @dev Note: Although there might be some small difference between the `assets_` amount and the actual amount\n // accredited at Liquidity due to BigMath rounding down, this amount is so small that it can be ignored.\n // because of BigMath precision of 7.2057594e16 for a coefficient size of 56, it would require >72 trillion DAI\n // to \"benefit\" 1 DAI in additional shares minted. Considering gas cost + APR per second, this ensures such\n // a manipulation attempt becomes extremely unlikely.\n\n // send funds to Liquidity protocol to generate yield\n (exchangePrice_, ) = LIQUIDITY.operate(\n address(ASSET),\n SafeCast.toInt256(assets_),\n 0,\n address(0),\n address(0),\n liquidityCallbackData_ // callback data. -> \"from\" for transferFrom in `liquidityCallback`\n );\n }\n\n /// @dev Withdraw `assets_` amount of tokens from Liquidity directly to `receiver_`\n /// @param assets_ The amount of tokens to withdraw\n /// @param receiver_ the receiver address of withdraw amount\n /// @return exchangePrice_ liquidity exchange price for token\n function _withdrawFromLiquidity(\n uint256 assets_,\n address receiver_\n ) internal virtual returns (uint256 exchangePrice_) {\n // @dev See similar comment in `_depositToLiquidity()` regarding burning a tiny bit of additional shares here\n // because of inaccuracies in Liquidity userSupply BigMath being rounded down.\n\n // get funds back from Liquidity protocol to send to the user\n (exchangePrice_, ) = LIQUIDITY.operate(\n address(ASSET),\n -SafeCast.toInt256(assets_),\n 0,\n receiver_,\n address(0),\n new bytes(0) // callback data -> withdraw doesn't trigger a callback\n );\n }\n\n /// @dev deposits `assets_` into liquidity and mints shares for `receiver_`. Returns amount of `sharesMinted_`.\n function _executeDeposit(\n uint256 assets_,\n address receiver_,\n bytes memory liquidityCallbackData_\n ) internal virtual validAddress(receiver_) returns (uint256 sharesMinted_) {\n // send funds to Liquidity protocol to generate yield -> returns updated liquidityExchangePrice\n uint256 tokenExchangePrice_ = _depositToLiquidity(assets_, liquidityCallbackData_);\n\n // update the exchange prices\n tokenExchangePrice_ = _updateRates(tokenExchangePrice_, false);\n\n // calculate the shares to mint\n // not using previewDeposit here because we just got newTokenExchangePrice_\n sharesMinted_ = (assets_ * EXCHANGE_PRICES_PRECISION) / tokenExchangePrice_;\n\n if (sharesMinted_ == 0) {\n revert FluidLendingError(ErrorTypes.fToken__DepositInsignificant);\n }\n\n _mint(receiver_, sharesMinted_);\n\n emit Deposit(msg.sender, receiver_, assets_, sharesMinted_);\n }\n\n /// @dev withdraws `assets_` from liquidity to `receiver_` and burns shares from `owner_`.\n /// Returns amount of `sharesBurned_`.\n /// requires nonReentrant! modifier on calling method otherwise ERC777s could reenter!\n function _executeWithdraw(\n uint256 assets_,\n address receiver_,\n address owner_\n ) internal virtual validAddress(receiver_) returns (uint256 sharesBurned_) {\n // burn shares for assets_ amount: assets_ * EXCHANGE_PRICES_PRECISION / updatedTokenTexchangePrice. Rounded up.\n // Note to be extra safe we do the shares burn before the withdrawFromLiquidity, even though that would return the\n // updated liquidityExchangePrice and thus save gas.\n sharesBurned_ = assets_.mulDivUp(EXCHANGE_PRICES_PRECISION, _updateRates(_getLiquidityExchangePrice(), false));\n\n /*\n The `mulDivUp` function is designed to round up the result of multiplication followed by division. \n Given non-zero `assets_` and the rounding-up behavior of this function, `sharesBurned_` will always \n be at least 1 if there's any remainder in the division.\n Thus, if `assets_` is non-zero, `sharesBurned_` can never be 0. The nature of the function ensures \n that even the smallest fractional result (greater than 0) will be rounded up to 1. Hence, there's no need \n to check for a rounding error that results in 0.\n Furthermore, if `assets_` was 0, an error 'UserModule__OperateAmountsZero' would already have been thrown \n during the `operate` function, ensuring the contract never reaches this point with a zero `assets_` value.\n Note: If ever the logic or the function behavior changes in the future, this assertion may need to be reconsidered.\n */\n\n _burn(owner_, sharesBurned_);\n\n // withdraw from liquidity directly to _receiver.\n _withdrawFromLiquidity(assets_, receiver_);\n\n emit Withdraw(msg.sender, receiver_, owner_, assets_, sharesBurned_);\n }\n}\n\n/// @notice fToken view methods. Implements view methods for ERC4626 compatibility\nabstract contract fTokenViews is fTokenCore {\n using FixedPointMathLib for uint256;\n\n /// @inheritdoc IFToken\n function getData()\n public\n view\n returns (\n IFluidLiquidity liquidity_,\n IFluidLendingFactory lendingFactory_,\n IFluidLendingRewardsRateModel lendingRewardsRateModel_,\n IAllowanceTransfer permit2_,\n address rebalancer_,\n bool rewardsActive_,\n uint256 liquidityBalance_,\n uint256 liquidityExchangePrice_,\n uint256 tokenExchangePrice_\n )\n {\n liquidityExchangePrice_ = _getLiquidityExchangePrice();\n\n bool rewardsEnded_;\n (tokenExchangePrice_, rewardsEnded_) = _calculateNewTokenExchangePrice(liquidityExchangePrice_);\n\n return (\n LIQUIDITY,\n LENDING_FACTORY,\n _rewardsRateModel,\n PERMIT2,\n _rebalancer,\n _rewardsActive && !rewardsEnded_,\n _getLiquidityBalance(),\n liquidityExchangePrice_,\n tokenExchangePrice_\n );\n }\n\n /// @inheritdoc IERC4626\n function asset() public view virtual override returns (address) {\n return address(ASSET);\n }\n\n /// @inheritdoc IERC4626\n function totalAssets() public view virtual override returns (uint256) {\n (uint256 tokenExchangePrice_, ) = _calculateNewTokenExchangePrice(_getLiquidityExchangePrice());\n return\n // all the underlying tokens are stored in Liquidity contract at all times\n (tokenExchangePrice_ * totalSupply()) / EXCHANGE_PRICES_PRECISION;\n }\n\n /// @inheritdoc IERC4626\n function convertToShares(uint256 assets_) public view virtual override returns (uint256) {\n (uint256 tokenExchangePrice_, ) = _calculateNewTokenExchangePrice(_getLiquidityExchangePrice());\n return assets_.mulDivDown(EXCHANGE_PRICES_PRECISION, tokenExchangePrice_);\n }\n\n /// @inheritdoc IERC4626\n function convertToAssets(uint256 shares_) public view virtual override returns (uint256) {\n (uint256 tokenExchangePrice_, ) = _calculateNewTokenExchangePrice(_getLiquidityExchangePrice());\n return shares_.mulDivDown(tokenExchangePrice_, EXCHANGE_PRICES_PRECISION);\n }\n\n /// @inheritdoc IERC4626\n /// @notice returned amount might be slightly different from actual amount at execution.\n function previewDeposit(uint256 assets_) public view virtual override returns (uint256) {\n return convertToShares(assets_);\n }\n\n /// @inheritdoc IERC4626\n function previewMint(uint256 shares_) public view virtual override returns (uint256) {\n (uint256 tokenExchangePrice_, ) = _calculateNewTokenExchangePrice(_getLiquidityExchangePrice());\n return shares_.mulDivUp(tokenExchangePrice_, EXCHANGE_PRICES_PRECISION);\n }\n\n /// @inheritdoc IERC4626\n function previewWithdraw(uint256 assets_) public view virtual override returns (uint256) {\n (uint256 tokenExchangePrice_, ) = _calculateNewTokenExchangePrice(_getLiquidityExchangePrice());\n return assets_.mulDivUp(EXCHANGE_PRICES_PRECISION, tokenExchangePrice_);\n }\n\n /// @inheritdoc IERC4626\n /// @notice returned amount might be slightly different from actual amount at execution.\n function previewRedeem(uint256 shares_) public view virtual override returns (uint256) {\n return convertToAssets(shares_);\n }\n\n /*//////////////////////////////////////////////////////////////\n DEPOSIT/WITHDRAWAL LIMIT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IERC4626\n function maxDeposit(address) public view virtual override returns (uint256) {\n // read total supplyInterest_ for the token at Liquidity and convert from BigMath\n uint256 supplyInterest_ = LIQUIDITY.readFromStorage(LIQUIDITY_TOTAL_AMOUNTS_SLOT) & LiquidityCalcs.X64;\n supplyInterest_ =\n (supplyInterest_ >> LiquidityCalcs.DEFAULT_EXPONENT_SIZE) <<\n (supplyInterest_ & LiquidityCalcs.DEFAULT_EXPONENT_MASK);\n\n unchecked {\n // normalize from raw\n supplyInterest_ = (supplyInterest_ * _getLiquidityExchangePrice()) / EXCHANGE_PRICES_PRECISION;\n // compare against hardcoded max possible value for total supply considering BigMath rounding down:\n // type(int128).max) after BigMath rounding (first 56 bits precision, then 71 bits getting set to 0)\n // so 1111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000\n // = 170141183460469229370504062281061498880. using minus 1\n if (supplyInterest_ > 170141183460469229370504062281061498879) {\n return 0;\n }\n // type(int128).max is the maximum interactable amount at Liquidity. But also total token amounts\n // must not overflow type(int128).max, so max depositable is type(int128).max - totalSupply.\n return uint256(uint128(type(int128).max)) - supplyInterest_;\n }\n }\n\n /// @inheritdoc IERC4626\n function maxMint(address) public view virtual override returns (uint256) {\n return convertToShares(maxDeposit(address(0)));\n }\n\n /// @inheritdoc IERC4626\n function maxWithdraw(address owner_) public view virtual override returns (uint256) {\n uint256 maxWithdrawableAtLiquidity_ = _getLiquidityWithdrawable();\n uint256 ownerBalance_ = convertToAssets(balanceOf(owner_));\n return maxWithdrawableAtLiquidity_ < ownerBalance_ ? maxWithdrawableAtLiquidity_ : ownerBalance_;\n }\n\n /// @inheritdoc IERC4626\n function maxRedeem(address owner_) public view virtual override returns (uint256) {\n uint256 maxWithdrawableAtLiquidity_ = convertToShares(_getLiquidityWithdrawable());\n uint256 ownerBalance_ = balanceOf(owner_);\n return maxWithdrawableAtLiquidity_ < ownerBalance_ ? maxWithdrawableAtLiquidity_ : ownerBalance_;\n }\n\n /// @inheritdoc IFToken\n function minDeposit() public view returns (uint256) {\n uint256 minBigMathRounding_ = 1 <<\n (LIQUIDITY.readFromStorage(LIQUIDITY_TOTAL_AMOUNTS_SLOT) & LiquidityCalcs.DEFAULT_EXPONENT_MASK); // 1 << total supply exponent\n uint256 previewMint_ = previewMint(1); // rounds up\n return minBigMathRounding_ > previewMint_ ? minBigMathRounding_ : previewMint_;\n }\n}\n\n/// @notice fToken admin related methods. fToken admins are Lending Factory auths. Possible actions are\n/// updating rewards, funding rewards, and rescuing any stuck funds (fToken contract itself never holds any funds).\nabstract contract fTokenAdmin is fTokenCore, fTokenViews {\n /// @dev checks if `msg.sender` is an allowed auth at LendingFactory. internal method instead of modifier\n /// to reduce bytecode size.\n function _checkIsLendingFactoryAuth() internal view {\n if (!LENDING_FACTORY.isAuth(msg.sender)) {\n revert FluidLendingError(ErrorTypes.fToken__Unauthorized);\n }\n }\n\n /// @inheritdoc IFTokenAdmin\n function updateRewards(IFluidLendingRewardsRateModel rewardsRateModel_) external {\n _checkIsLendingFactoryAuth();\n\n // @dev no check for address zero needed here, as that is actually explicitly checked where _rewardsRateModel\n // is used. In fact it is beneficial to set _rewardsRateModel to address zero when there are no rewards.\n\n // apply current rewards rate before updating to new one\n updateRates();\n\n _rewardsRateModel = rewardsRateModel_;\n\n // set flag _rewardsActive\n _rewardsActive = address(rewardsRateModel_) != address(0);\n\n emit LogUpdateRewards(rewardsRateModel_);\n }\n\n /// @inheritdoc IFTokenAdmin\n function rebalance() external payable virtual nonReentrant returns (uint256 assets_) {\n if (msg.sender != _rebalancer) {\n revert FluidLendingError(ErrorTypes.fToken__NotRebalancer);\n }\n if (msg.value > 0) {\n revert FluidLendingError(ErrorTypes.fToken__NotNativeUnderlying);\n }\n // calculating difference in assets. if liquidity balance is bigger it'll throw which is an expected behaviour\n assets_ = totalAssets() - _getLiquidityBalance();\n // send funds to Liquidity protocol\n uint256 liquidityExchangePrice_ = _depositToLiquidity(assets_, abi.encode(msg.sender));\n\n // update the exchange prices, always updating on storage\n _updateRates(liquidityExchangePrice_, true);\n\n // no shares are minted when funding fToken contract for rewards\n\n emit LogRebalance(assets_);\n }\n\n /// @inheritdoc IFTokenAdmin\n function updateRebalancer(address newRebalancer_) public validAddress(newRebalancer_) {\n _checkIsLendingFactoryAuth();\n\n _rebalancer = newRebalancer_;\n\n emit LogUpdateRebalancer(newRebalancer_);\n }\n\n /// @inheritdoc IFTokenAdmin\n function updateRates() public returns (uint256 tokenExchangePrice_, uint256 liquidityExchangePrice_) {\n liquidityExchangePrice_ = _getLiquidityExchangePrice();\n tokenExchangePrice_ = _updateRates(liquidityExchangePrice_, true);\n }\n\n /// @inheritdoc IFTokenAdmin\n //\n // @dev this contract never holds any funds:\n // -> deposited funds are directly sent to Liquidity.\n // -> rewards are also stored at Liquidity.\n function rescueFunds(address token_) external virtual nonReentrant {\n _checkIsLendingFactoryAuth();\n SafeTransfer.safeTransfer(address(token_), address(LIQUIDITY), IERC20(token_).balanceOf(address(this)));\n emit LogRescueFunds(token_);\n }\n}\n\n/// @notice fToken public executable actions: deposit, mint, mithdraw and redeem.\n/// All actions are optionally also available with an additional param to limit the maximum slippage, e.g. maximum\n/// assets used for minting x amount of shares.\nabstract contract fTokenActions is fTokenCore, fTokenViews {\n /// @dev reverts if `amount_` is < `minAmountOut_`. Used to reduce bytecode size.\n function _revertIfBelowMinAmountOut(uint256 amount_, uint256 minAmountOut_) internal pure {\n if (amount_ < minAmountOut_) {\n revert FluidLendingError(ErrorTypes.fToken__MinAmountOut);\n }\n }\n\n /// @dev reverts if `amount_` is > `maxAmount_`. Used to reduce bytecode size.\n function _revertIfAboveMaxAmount(uint256 amount_, uint256 maxAmount_) internal pure {\n if (amount_ > maxAmount_) {\n revert FluidLendingError(ErrorTypes.fToken__MaxAmount);\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n DEPOSIT\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IERC4626\n /// @notice If `assets_` equals uint256.max then the whole balance of `msg.sender` is deposited.\n /// `assets_` must at least be `minDeposit()` amount; reverts `fToken__DepositInsignificant()` if not.\n /// Recommended to use `deposit()` with a `minAmountOut_` param instead to set acceptable limit.\n /// @return shares_ actually minted shares\n function deposit(\n uint256 assets_,\n address receiver_\n ) public virtual override nonReentrant returns (uint256 shares_) {\n if (assets_ == type(uint256).max) {\n assets_ = ASSET.balanceOf(msg.sender);\n }\n\n // @dev transfer of tokens from `msg.sender` to liquidity contract happens via `liquidityCallback`\n shares_ = _executeDeposit(assets_, receiver_, abi.encode(msg.sender));\n }\n\n /// @notice same as {fToken-deposit} but with an additional setting for minimum output amount.\n /// reverts with `fToken__MinAmountOut()` if `minAmountOut_` of shares is not reached\n function deposit(uint256 assets_, address receiver_, uint256 minAmountOut_) external returns (uint256 shares_) {\n shares_ = deposit(assets_, receiver_);\n _revertIfBelowMinAmountOut(shares_, minAmountOut_);\n }\n\n /*//////////////////////////////////////////////////////////////\n MINT \n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IERC4626\n /// @notice If `shares_` equals uint256.max then the whole balance of `msg.sender` is deposited.\n /// `shares_` must at least be `minMint()` amount; reverts `fToken__DepositInsignificant()` if not.\n /// Note there might be tiny inaccuracies between requested `shares_` and actually received shares amount.\n /// Recommended to use `deposit()` over mint because it is more gas efficient and less likely to revert.\n /// Recommended to use `mint()` with a `minAmountOut_` param instead to set acceptable limit.\n /// @return assets_ deposited assets amount\n function mint(uint256 shares_, address receiver_) public virtual override nonReentrant returns (uint256 assets_) {\n if (shares_ == type(uint256).max) {\n assets_ = ASSET.balanceOf(msg.sender);\n } else {\n // No need to check for rounding error, previewMint rounds up.\n assets_ = previewMint(shares_);\n }\n\n // @dev transfer of tokens from `msg.sender` to liquidity contract happens via `liquidityCallback`\n\n _executeDeposit(assets_, receiver_, abi.encode(msg.sender));\n }\n\n /// @notice same as {fToken-mint} but with an additional setting for maximum assets input amount.\n /// reverts with `fToken__MaxAmount()` if `maxAssets_` of assets is surpassed to mint `shares_`.\n function mint(uint256 shares_, address receiver_, uint256 maxAssets_) external returns (uint256 assets_) {\n assets_ = mint(shares_, receiver_);\n _revertIfAboveMaxAmount(assets_, maxAssets_);\n }\n\n /*//////////////////////////////////////////////////////////////\n WITHDRAW\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IERC4626\n /// @notice If `assets_` equals uint256.max then the whole fToken balance of `owner_` is withdrawn. This does not\n /// consider withdrawal limit at Liquidity so best to check with `maxWithdraw()` before.\n /// Note there might be tiny inaccuracies between requested `assets_` and actually received assets amount.\n /// Recommended to use `withdraw()` with a `minAmountOut_` param instead to set acceptable limit.\n /// @return shares_ burned shares\n function withdraw(\n uint256 assets_,\n address receiver_,\n address owner_\n ) public virtual override nonReentrant returns (uint256 shares_) {\n if (assets_ == type(uint256).max) {\n assets_ = previewRedeem(balanceOf(owner_));\n }\n shares_ = _executeWithdraw(assets_, receiver_, owner_);\n\n if (msg.sender != owner_) {\n _spendAllowance(owner_, msg.sender, shares_);\n }\n }\n\n /// @notice same as {fToken-withdraw} but with an additional setting for maximum shares burned.\n /// reverts with `fToken__MaxAmount()` if `maxSharesBurn_` of shares burned is surpassed.\n function withdraw(\n uint256 assets_,\n address receiver_,\n address owner_,\n uint256 maxSharesBurn_\n ) external returns (uint256 shares_) {\n shares_ = withdraw(assets_, receiver_, owner_);\n _revertIfAboveMaxAmount(shares_, maxSharesBurn_);\n }\n\n /*//////////////////////////////////////////////////////////////\n REDEEM\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IERC4626\n /// @notice If `shares_` equals uint256.max then the whole balance of `owner_` is withdrawn.This does not\n /// consider withdrawal limit at Liquidity so best to check with `maxRedeem()` before.\n /// Recommended to use `withdraw()` over redeem because it is more gas efficient and can set specific amount.\n /// Recommended to use `redeem()` with a `minAmountOut_` param instead to set acceptable limit.\n /// @return assets_ withdrawn assets amount\n function redeem(\n uint256 shares_,\n address receiver_,\n address owner_\n ) public virtual override nonReentrant returns (uint256 assets_) {\n if (shares_ == type(uint256).max) {\n shares_ = balanceOf(owner_);\n }\n\n assets_ = previewRedeem(shares_);\n\n uint256 burnedShares_ = _executeWithdraw(assets_, receiver_, owner_);\n\n if (msg.sender != owner_) {\n _spendAllowance(owner_, msg.sender, burnedShares_);\n }\n }\n\n /// @notice same as {fToken-redeem} but with an additional setting for minimum output amount.\n /// reverts with `fToken__MinAmountOut()` if `minAmountOut_` of assets is not reached.\n function redeem(\n uint256 shares_,\n address receiver_,\n address owner_,\n uint256 minAmountOut_\n ) external returns (uint256 assets_) {\n assets_ = redeem(shares_, receiver_, owner_);\n _revertIfBelowMinAmountOut(assets_, minAmountOut_);\n }\n}\n\n/// @notice fTokens support EIP-2612 permit approvals via signature so this contract implements\n/// withdrawals (withdraw / redeem) with signature used for approval of the fToken shares.\nabstract contract fTokenEIP2612Withdrawals is fTokenActions {\n /// @dev creates `sharesToPermit_` allowance for `owner_` via EIP2612 `deadline_` and `signature_`\n function _allowViaPermitEIP2612(\n address owner_,\n uint256 sharesToPermit_,\n uint256 deadline_,\n bytes calldata signature_\n ) internal {\n (uint8 v_, bytes32 r_, bytes32 s_) = _splitSignature(signature_);\n // spender = msg.sender\n permit(owner_, msg.sender, sharesToPermit_, deadline_, v_, r_, s_);\n }\n\n /// @notice withdraw amount of `assets_` with ERC-2612 permit signature for fToken approval.\n /// `owner_` signs ERC-2612 permit `signature_` to give allowance of fTokens to `msg.sender`.\n /// Note there might be tiny inaccuracies between requested `assets_` and actually received assets amount.\n /// allowance via signature (`sharesToPermit_`) should cover `previewWithdraw(assets_)` plus a little buffer to avoid revert.\n /// Inherent trust assumption that `msg.sender` will set `receiver_` and `maxSharesBurn_` as `owner_` intends\n /// (which is always the case when giving allowance to some spender).\n /// @param sharesToPermit_ shares amount to use for EIP2612 permit(). Should cover `previewWithdraw(assets_)` + small buffer.\n /// @param assets_ amount of assets to withdraw\n /// @param receiver_ receiver of withdrawn assets\n /// @param owner_ owner to withdraw from (must be signature signer)\n /// @param maxSharesBurn_ maximum accepted amount of shares burned\n /// @param deadline_ deadline for signature validity\n /// @param signature_ packed signature of signing the EIP712 hash for ERC-2612 permit\n /// @return shares_ burned shares amount\n function withdrawWithSignature(\n uint256 sharesToPermit_,\n uint256 assets_,\n address receiver_,\n address owner_,\n uint256 maxSharesBurn_,\n uint256 deadline_,\n bytes calldata signature_\n ) external virtual nonReentrant returns (uint256 shares_) {\n if (msg.sender == owner_) {\n // no sense in operating with permit if msg.sender is owner. should call normal `withdraw()` instead.\n revert FluidLendingError(ErrorTypes.fToken__PermitFromOwnerCall);\n }\n\n // create allowance through signature_\n _allowViaPermitEIP2612(owner_, sharesToPermit_, deadline_, signature_);\n\n // execute withdraw to get shares_ to spend amount\n shares_ = _executeWithdraw(assets_, receiver_, owner_);\n\n _revertIfAboveMaxAmount(shares_, maxSharesBurn_);\n\n _spendAllowance(owner_, msg.sender, shares_);\n }\n\n /// @notice redeem amount of `shares_` with ERC-2612 permit signature for fToken approval.\n /// `owner_` signs ERC-2612 permit `signature_` to give allowance of fTokens to `msg.sender`.\n /// Note there might be tiny inaccuracies between requested `shares_` to redeem and actually burned shares.\n /// allowance via signature must cover `shares_` plus a tiny buffer.\n /// Inherent trust assumption that `msg.sender` will set `receiver_` and `minAmountOut_` as `owner_` intends\n /// (which is always the case when giving allowance to some spender).\n /// Recommended to use `withdraw()` over redeem because it is more gas efficient and can set specific amount.\n /// @param shares_ amount of shares to redeem\n /// @param receiver_ receiver of withdrawn assets\n /// @param owner_ owner to withdraw from (must be signature signer)\n /// @param minAmountOut_ minimum accepted amount of assets withdrawn\n /// @param deadline_ deadline for signature validity\n /// @param signature_ packed signature of signing the EIP712 hash for ERC-2612 permit\n /// @return assets_ withdrawn assets amount\n function redeemWithSignature(\n uint256 shares_,\n address receiver_,\n address owner_,\n uint256 minAmountOut_,\n uint256 deadline_,\n bytes calldata signature_\n ) external virtual nonReentrant returns (uint256 assets_) {\n if (msg.sender == owner_) {\n // no sense in operating with permit if msg.sender is owner. should call normal `redeem()` instead.\n revert FluidLendingError(ErrorTypes.fToken__PermitFromOwnerCall);\n }\n\n assets_ = previewRedeem(shares_);\n _revertIfBelowMinAmountOut(assets_, minAmountOut_);\n\n // create allowance through signature_\n _allowViaPermitEIP2612(owner_, shares_, deadline_, signature_);\n\n // execute withdraw to get actual shares to spend amount\n uint256 sharesToSpend_ = _executeWithdraw(assets_, receiver_, owner_);\n\n _spendAllowance(owner_, msg.sender, sharesToSpend_);\n }\n}\n\n/// @notice implements fTokens support for deposit / mint via EIP-2612 permit.\n/// @dev methods revert if underlying asset does not support EIP-2612.\nabstract contract fTokenEIP2612Deposits is fTokenActions {\n /// @notice deposit `assets_` amount with EIP-2612 Permit2 signature for underlying asset approval.\n /// IMPORTANT: This will revert if the underlying `asset()` does not support EIP-2612.\n /// reverts with `fToken__MinAmountOut()` if `minAmountOut_` of shares is not reached.\n /// `assets_` must at least be `minDeposit()` amount; reverts `fToken__DepositInsignificant()` if not.\n /// @param assets_ amount of assets to deposit\n /// @param receiver_ receiver of minted fToken shares\n /// @param minAmountOut_ minimum accepted amount of shares minted\n /// @param deadline_ deadline for signature validity\n /// @param signature_ packed signature of signing the EIP712 hash for EIP-2612 Permit\n /// @return shares_ amount of minted shares\n function depositWithSignatureEIP2612(\n uint256 assets_,\n address receiver_,\n uint256 minAmountOut_,\n uint256 deadline_,\n bytes calldata signature_\n ) external returns (uint256 shares_) {\n // create allowance through signature_ and spend it\n (uint8 v_, bytes32 r_, bytes32 s_) = _splitSignature(signature_);\n\n // EIP-2612 permit for underlying asset from owner (msg.sender) to spender (this contract)\n IERC20Permit(address(ASSET)).permit(msg.sender, address(this), assets_, deadline_, v_, r_, s_);\n\n // deposit() includes nonReentrant modifier which is enough to have from this point forward\n shares_ = deposit(assets_, receiver_);\n _revertIfBelowMinAmountOut(shares_, minAmountOut_);\n }\n\n /// @notice mint amount of `shares_` with EIP-2612 Permit signature for underlying asset approval.\n /// IMPORTANT: This will revert if the underlying `asset()` does not support EIP-2612.\n /// Signature should approve a little bit more than expected assets amount (`previewMint()`) to avoid reverts.\n /// `shares_` must at least be `minMint()` amount; reverts with `fToken__DepositInsignificant()` if not.\n /// Note there might be tiny inaccuracies between requested `shares_` and actually received shares amount.\n /// Recommended to use `deposit()` over mint because it is more gas efficient and less likely to revert.\n /// @param shares_ amount of shares to mint\n /// @param receiver_ receiver of minted fToken shares\n /// @param maxAssets_ maximum accepted amount of assets used as input to mint `shares_`\n /// @param deadline_ deadline for signature validity\n /// @param signature_ packed signature of signing the EIP712 hash for EIP-2612 Permit\n /// @return assets_ deposited assets amount\n function mintWithSignatureEIP2612(\n uint256 shares_,\n address receiver_,\n uint256 maxAssets_,\n uint256 deadline_,\n bytes calldata signature_\n ) external returns (uint256 assets_) {\n assets_ = previewMint(shares_);\n\n // create allowance through signature_ and spend it\n (uint8 v_, bytes32 r_, bytes32 s_) = _splitSignature(signature_);\n\n // EIP-2612 permit for underlying asset from owner (msg.sender) to spender (this contract)\n IERC20Permit(address(ASSET)).permit(msg.sender, address(this), assets_, deadline_, v_, r_, s_);\n\n // mint() includes nonReentrant modifier which is enough to have from this point forward\n assets_ = mint(shares_, receiver_);\n _revertIfAboveMaxAmount(assets_, maxAssets_);\n }\n}\n\n/// @notice implements fTokens support for deposit / mint via Permit2 signature.\nabstract contract fTokenPermit2Deposits is fTokenActions {\n /// @inheritdoc IFToken\n function depositWithSignature(\n uint256 assets_,\n address receiver_,\n uint256 minAmountOut_,\n IAllowanceTransfer.PermitSingle calldata permit_,\n bytes calldata signature_\n ) external nonReentrant returns (uint256 shares_) {\n // give allowance to address(this) via Permit2 signature -> to spend allowance in LiquidityCallback\n // to transfer funds directly from msg.sender to liquidity\n PERMIT2.permit(\n // owner - Who signed the permit and also holds the tokens\n // @dev Note if this is modified to not be msg.sender, extra steps would be needed for security!\n // the caller could use this signature and deposit to the balance of receiver_, which could be set to any address,\n // because it is not included in the signature. Use permitWitnessTransferFrom in that case. Same for `minAmountOut_`.\n msg.sender,\n permit_, // permit message\n signature_ // packed signature of signing the EIP712 hash of `permit_`\n );\n\n // @dev transfer of tokens from `msg.sender` to liquidity contract happens via `liquidityCallback`\n\n shares_ = _executeDeposit(assets_, receiver_, abi.encode(true, msg.sender));\n _revertIfBelowMinAmountOut(shares_, minAmountOut_);\n }\n\n /// @inheritdoc IFToken\n function mintWithSignature(\n uint256 shares_,\n address receiver_,\n uint256 maxAssets_,\n IAllowanceTransfer.PermitSingle calldata permit_,\n bytes calldata signature_\n ) external nonReentrant returns (uint256 assets_) {\n assets_ = previewMint(shares_);\n _revertIfAboveMaxAmount(assets_, maxAssets_);\n\n // give allowance to address(this) via Permit2 PermitSingle. to spend allowance in LiquidityCallback\n // to transfer funds directly from msg.sender to liquidity\n PERMIT2.permit(\n // owner - Who signed the permit and also holds the tokens\n // @dev Note if this is modified to not be msg.sender, extra steps would be needed for security!\n // the caller could use this signature and deposit to the balance of receiver_, which could be set to any address,\n // because it is not included in the signature. Use permitWitnessTransferFrom in that case. Same for `minAmountOut_`.\n msg.sender,\n permit_, // permit message\n signature_ // packed signature of signing the EIP712 hash of `permit_`\n );\n\n // @dev transfer of tokens from `msg.sender` to liquidity contract happens via `liquidityCallback`\n\n _executeDeposit(assets_, receiver_, abi.encode(true, msg.sender));\n }\n}\n\n/// @title Fluid fToken (Lending with interest)\n/// @notice fToken is a token that can be used to supply liquidity to the Fluid Liquidity pool and earn interest for doing so.\n/// The fToken is backed by the underlying balance and can be redeemed for the underlying token at any time.\n/// The interest is earned via Fluid Liquidity, e.g. because borrowers pay a borrow rate on it. In addition, fTokens may also\n/// have active rewards going on that count towards the earned yield for fToken holders.\n/// @dev The fToken implements the ERC20 and ERC4626 standard, which means it can be transferred, minted and burned.\n/// The fToken supports EIP-2612 permit approvals via signature.\n/// The fToken implements withdrawals via EIP-2612 permits and deposits with Permit2 or EIP-2612 (if underlying supports it) signatures.\n/// fTokens are not upgradeable.\n/// @dev For view methods / accessing data, use the \"LendingResolver\" periphery contract.\ncontract fToken is fTokenAdmin, fTokenActions, fTokenEIP2612Withdrawals, fTokenPermit2Deposits, fTokenEIP2612Deposits {\n /// @param liquidity_ liquidity contract address\n /// @param lendingFactory_ lending factory contract address\n /// @param asset_ underlying token address\n constructor(\n IFluidLiquidity liquidity_,\n IFluidLendingFactory lendingFactory_,\n IERC20 asset_\n ) Variables(liquidity_, lendingFactory_, asset_) {\n // set initial values for _liquidityExchangePrice, _tokenExchangePrice and _lastUpdateTimestamp\n _liquidityExchangePrice = uint64(_getLiquidityExchangePrice());\n _tokenExchangePrice = uint64(EXCHANGE_PRICES_PRECISION);\n _lastUpdateTimestamp = uint40(block.timestamp);\n }\n\n /// @inheritdoc IERC20Metadata\n function decimals() public view virtual override(ERC20, IERC20Metadata) returns (uint8) {\n return DECIMALS;\n }\n\n /// @inheritdoc IFToken\n function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external virtual override {\n if (msg.sender != address(LIQUIDITY) || token_ != address(ASSET) || _status != REENTRANCY_ENTERED) {\n // caller must be liquidity, token must match, and reentrancy status must be REENTRANCY_ENTERED\n revert FluidLendingError(ErrorTypes.fToken__Unauthorized);\n }\n\n // callback data can be a) an address only b) an address + transfer via permit2 flag set to true\n // for a) length will be 32, for b) length is 64\n if (data_.length == 32) {\n address from_ = abi.decode(data_, (address));\n\n // transfer `amount_` from `from_` (original deposit msg.sender) to liquidity contract\n SafeTransfer.safeTransferFrom(address(ASSET), from_, address(LIQUIDITY), amount_);\n } else {\n (bool isPermit2_, address from_) = abi.decode(data_, (bool, address));\n if (!isPermit2_) {\n // unexepcted liquidity callback data\n revert FluidLendingError(ErrorTypes.fToken__InvalidParams);\n }\n\n // transfer `amount_` from `from_` (original deposit msg.sender) to liquidity contract via PERMIT2\n PERMIT2.transferFrom(from_, address(LIQUIDITY), uint160(amount_), address(ASSET));\n }\n }\n}\n"
|
||
},
|
||
"contracts/protocols/lending/fToken/nativeUnderlying/fTokenNativeUnderlying.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { FixedPointMathLib } from \"solmate/src/utils/FixedPointMathLib.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { SafeTransfer } from \"../../../../libraries/safeTransfer.sol\";\nimport { LiquiditySlotsLink } from \"../../../../libraries/liquiditySlotsLink.sol\";\nimport { ErrorTypes } from \"../../errorTypes.sol\";\nimport { fTokenCore, fTokenAdmin, fToken } from \"../main.sol\";\n\nimport { IWETH9 } from \"../../interfaces/external/iWETH9.sol\";\nimport { IFluidLendingFactory } from \"../../interfaces/iLendingFactory.sol\";\nimport { IFTokenAdmin, IFTokenNativeUnderlying, IFToken } from \"../../interfaces/iFToken.sol\";\nimport { IFluidLiquidity } from \"../../../../liquidity/interfaces/iLiquidity.sol\";\n\n/// @dev overrides certain methods from the inherited fToken used as base contract to make them compatible with\n/// the native token being used as underlying.\nabstract contract fTokenNativeUnderlyingOverrides is fToken, IFTokenNativeUnderlying {\n using FixedPointMathLib for uint256;\n\n /// @inheritdoc IFTokenNativeUnderlying\n address public constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @dev gets asset address for liquidity slot links, overridden to set native token address\n function _getLiquiditySlotLinksAsset() internal view virtual override returns (address) {\n return NATIVE_TOKEN_ADDRESS;\n }\n\n /// @dev Gets current Liquidity underlying token balance\n function _getLiquidityUnderlyingBalance() internal view virtual override returns (uint256) {\n return address(LIQUIDITY).balance;\n }\n\n /// @inheritdoc IFTokenAdmin\n function rescueFunds(address token_) external virtual override(IFTokenAdmin, fTokenAdmin) nonReentrant {\n _checkIsLendingFactoryAuth();\n\n if (token_ == NATIVE_TOKEN_ADDRESS) {\n Address.sendValue(payable(address(LIQUIDITY)), address(this).balance);\n } else {\n SafeTransfer.safeTransfer(address(token_), address(LIQUIDITY), IERC20(token_).balanceOf(address(this)));\n }\n\n emit LogRescueFunds(token_);\n }\n\n /*//////////////////////////////////////////////////////////////\n REWARDS\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc fTokenAdmin\n function rebalance()\n external\n payable\n virtual\n override(IFTokenAdmin, fTokenAdmin)\n nonReentrant\n returns (uint256 assets_)\n {\n if (msg.sender != _rebalancer) {\n revert FluidLendingError(ErrorTypes.fToken__NotRebalancer);\n }\n // calculating difference in assets. if liquidity balance is bigger it'll throw which is an expected behaviour\n assets_ = totalAssets() - _getLiquidityBalance();\n\n if (msg.value < assets_) {\n assets_ = msg.value;\n } else if (msg.value > assets_) {\n // send back overfunded msg.value amount\n Address.sendValue(payable(msg.sender), msg.value - assets_);\n }\n\n // send funds to Liquidity protocol to generate yield\n uint256 liquidityExchangePrice_ = _depositToLiquidity(assets_, new bytes(0));\n\n // update the exchange prices, always updating on storage\n _updateRates(liquidityExchangePrice_, true);\n\n // no shares are minted when funding fToken contract for rewards\n\n emit LogRebalance(assets_);\n }\n\n /*//////////////////////////////////////////////////////////////\n DEPOSIT\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc fTokenCore\n function _depositToLiquidity(\n uint256 assets_,\n bytes memory liquidityCallbackData_\n ) internal virtual override returns (uint256 exchangePrice_) {\n // send funds to Liquidity protocol to generate yield, send along msg.value\n (exchangePrice_, ) = LIQUIDITY.operate{ value: assets_ }(\n NATIVE_TOKEN_ADDRESS, // deposit to Liquidity is always in native, also if user input is wrapped token\n SafeCast.toInt256(assets_),\n 0,\n address(0),\n address(0),\n liquidityCallbackData_ // callback data. -> \"from\" for transferFrom in `liquidityCallback`\n );\n }\n\n /// @inheritdoc fTokenCore\n function _executeDeposit(\n uint256 assets_,\n address receiver_,\n // liquidityCallbackData_ not needed for native transfer, sent along as msg.value. But used to recognize Permit2 transfers.\n bytes memory liquidityCallbackData_\n ) internal virtual override returns (uint256 sharesMinted_) {\n // transfer wrapped asset from user to this contract\n if (liquidityCallbackData_.length > 32) {\n // liquidityCallbackData_ with length > 32 can only be Permit2 as all others maximally encode from address\n PERMIT2.transferFrom(msg.sender, address(this), uint160(assets_), address(ASSET));\n } else {\n SafeTransfer.safeTransferFrom(address(ASSET), msg.sender, address(this), assets_);\n }\n\n // convert WETH to native underlying token\n IWETH9(address(ASSET)).withdraw(assets_);\n\n // super._executeDeposit includes check for validAddress receiver_\n return super._executeDeposit(assets_, receiver_, new bytes(0));\n }\n\n /// @dev deposits `msg.value` amount of native token into liquidity and mints shares for `receiver_`.\n /// Returns amount of `sharesMinted_`.\n function _executeDepositNative(address receiver_) internal virtual returns (uint256 sharesMinted_) {\n // super._executeDeposit includes check for validAddress receiver_\n return super._executeDeposit(msg.value, receiver_, new bytes(0));\n }\n\n /*//////////////////////////////////////////////////////////////\n WITHDRAW\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc fTokenCore\n function _withdrawFromLiquidity(\n uint256 assets_,\n address receiver_\n ) internal virtual override returns (uint256 exchangePrice_) {\n // get funds back from Liquidity protocol to send to the user\n (exchangePrice_, ) = LIQUIDITY.operate(\n NATIVE_TOKEN_ADDRESS, // withdraw from Liquidity is always in native, also if user output is wrapped token\n -SafeCast.toInt256(assets_),\n 0,\n receiver_,\n address(0),\n new bytes(0) // callback data -> withdraw doesn't trigger a callback\n );\n }\n\n /// @inheritdoc fTokenCore\n function _executeWithdraw(\n uint256 assets_,\n address receiver_,\n address owner_\n ) internal virtual override returns (uint256 sharesBurned_) {\n // super._executeWithdraw includes check for validAddress(receiver_)\n\n // withdraw from liquidity to this contract first to convert withdrawn native token to wrapped native for _receiver.\n sharesBurned_ = super._executeWithdraw(assets_, address(this), owner_);\n\n // convert received native underlying token to WETH and transfer to receiver_\n IWETH9(address(ASSET)).deposit{ value: assets_ }();\n SafeTransfer.safeTransfer(address(ASSET), receiver_, assets_);\n }\n\n /// @dev withdraws `assets_` from liquidity to `receiver_` and burns shares from `owner_`.\n /// Returns amount of `sharesBurned_`.\n function _executeWithdrawNative(\n uint256 assets_,\n address receiver_,\n address owner_\n ) internal virtual returns (uint256 sharesBurned_) {\n // super._executeWithdraw includes check for validAddress(receiver_)\n return super._executeWithdraw(assets_, receiver_, owner_);\n }\n}\n\n/// @notice implements deposit / mint / withdraw / redeem actions with Native token being used as interaction token.\nabstract contract fTokenNativeUnderlyingActions is fTokenNativeUnderlyingOverrides {\n /*//////////////////////////////////////////////////////////////\n DEPOSIT\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IFTokenNativeUnderlying\n function depositNative(address receiver_) public payable nonReentrant returns (uint256 shares_) {\n shares_ = _executeDepositNative(receiver_);\n }\n\n /// @inheritdoc IFTokenNativeUnderlying\n function depositNative(address receiver_, uint256 minAmountOut_) external payable returns (uint256 shares_) {\n shares_ = depositNative(receiver_);\n _revertIfBelowMinAmountOut(shares_, minAmountOut_);\n }\n\n /*//////////////////////////////////////////////////////////////\n MINT \n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IFTokenNativeUnderlying\n function mintNative(uint256 shares_, address receiver_) public payable nonReentrant returns (uint256 assets_) {\n // No need to check for rounding error, previewMint rounds up.\n assets_ = previewMint(shares_);\n\n if (msg.value < assets_) {\n // not enough msg.value sent along to cover mint shares amount\n revert FluidLendingError(ErrorTypes.fTokenNativeUnderlying__TransferInsufficient);\n }\n\n _executeDepositNative(receiver_);\n }\n\n /// @inheritdoc IFTokenNativeUnderlying\n function mintNative(\n uint256 shares_,\n address receiver_,\n uint256 maxAssets_\n ) external payable returns (uint256 assets_) {\n assets_ = mintNative(shares_, receiver_);\n _revertIfAboveMaxAmount(assets_, maxAssets_);\n }\n\n /*//////////////////////////////////////////////////////////////\n WITHDRAW\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IFTokenNativeUnderlying\n function withdrawNative(\n uint256 assets_,\n address receiver_,\n address owner_\n ) public nonReentrant returns (uint256 shares_) {\n if (assets_ == type(uint256).max) {\n assets_ = previewRedeem(balanceOf(msg.sender));\n }\n\n shares_ = _executeWithdrawNative(assets_, receiver_, owner_);\n\n if (msg.sender != owner_) {\n _spendAllowance(owner_, msg.sender, shares_);\n }\n }\n\n /// @inheritdoc IFTokenNativeUnderlying\n function withdrawNative(\n uint256 assets_,\n address receiver_,\n address owner_,\n uint256 maxSharesBurn_\n ) external returns (uint256 shares_) {\n shares_ = withdrawNative(assets_, receiver_, owner_);\n _revertIfAboveMaxAmount(shares_, maxSharesBurn_);\n }\n\n /*//////////////////////////////////////////////////////////////\n REDEEM\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IFTokenNativeUnderlying\n function redeemNative(\n uint256 shares_,\n address receiver_,\n address owner_\n ) public nonReentrant returns (uint256 assets_) {\n if (shares_ == type(uint256).max) {\n shares_ = balanceOf(msg.sender);\n }\n\n assets_ = previewRedeem(shares_);\n\n uint256 burnedShares_ = _executeWithdrawNative(assets_, receiver_, owner_);\n\n if (msg.sender != owner_) {\n _spendAllowance(owner_, msg.sender, burnedShares_);\n }\n }\n\n /// @inheritdoc IFTokenNativeUnderlying\n function redeemNative(\n uint256 shares_,\n address receiver_,\n address owner_,\n uint256 minAmountOut_\n ) external returns (uint256 assets_) {\n assets_ = redeemNative(shares_, receiver_, owner_);\n _revertIfBelowMinAmountOut(assets_, minAmountOut_);\n }\n}\n\n/// @notice fTokens support EIP-2612 permit approvals via signature so withdrawals are possible with signature.\n/// This contract implements those withdrawals for a native underlying asset.\nabstract contract fTokenNativeUnderlyingEIP2612Withdrawals is fTokenNativeUnderlyingActions {\n /// @inheritdoc IFTokenNativeUnderlying\n function withdrawWithSignatureNative(\n uint256 sharesToPermit_,\n uint256 assets_,\n address receiver_,\n address owner_,\n uint256 maxSharesBurn_,\n uint256 deadline_,\n bytes calldata signature_\n ) external nonReentrant returns (uint256 shares_) {\n // @dev logic below is exactly the same as in {fTokenEIP2612Withdrawals-withdrawWithSignature}, just using\n // _executeWithdrawNative instead of _executeWithdraw\n\n if (msg.sender == owner_) {\n // no sense in operating with permit if msg.sender is owner. should call normal `withdraw()` instead.\n revert FluidLendingError(ErrorTypes.fToken__PermitFromOwnerCall);\n }\n\n // create allowance through signature_\n _allowViaPermitEIP2612(owner_, sharesToPermit_, deadline_, signature_);\n\n // execute withdraw to get shares_ to spend amount\n shares_ = _executeWithdrawNative(assets_, receiver_, owner_);\n\n _revertIfAboveMaxAmount(shares_, maxSharesBurn_);\n\n _spendAllowance(owner_, msg.sender, shares_);\n }\n\n /// @inheritdoc IFTokenNativeUnderlying\n function redeemWithSignatureNative(\n uint256 shares_,\n address receiver_,\n address owner_,\n uint256 minAmountOut_,\n uint256 deadline_,\n bytes calldata signature_\n ) external nonReentrant returns (uint256 assets_) {\n // @dev logic below is exactly the same as in {fTokenEIP2612Withdrawals-redeemWithSignature}, just using\n // _executeWithdrawNative instead of _executeWithdraw\n\n if (msg.sender == owner_) {\n // no sense in operating with permit if msg.sender is owner. should call normal `redeem()` instead.\n revert FluidLendingError(ErrorTypes.fToken__PermitFromOwnerCall);\n }\n\n assets_ = previewRedeem(shares_);\n _revertIfBelowMinAmountOut(assets_, minAmountOut_);\n\n // create allowance through signature_\n _allowViaPermitEIP2612(owner_, shares_, deadline_, signature_);\n\n // execute withdraw to get actual shares to spend amount\n uint256 sharesToSpend_ = _executeWithdrawNative(assets_, receiver_, owner_);\n\n _spendAllowance(owner_, msg.sender, sharesToSpend_);\n }\n}\n\n/// @notice Same as the {fToken} contract but with support for native token as underlying asset.\n/// Actual underlying asset is the wrapped native ERC20 version (e.g. WETH), which acts like any other fToken.\n/// But in addition the fTokenNativeUnderlying also has methods for doing all the same actions via the native token.\ncontract fTokenNativeUnderlying is fTokenNativeUnderlyingEIP2612Withdrawals {\n /// @param liquidity_ liquidity contract address\n /// @param lendingFactory_ lending factory contract address\n /// @param weth_ address of wrapped native token (e.g. WETH)\n constructor(\n IFluidLiquidity liquidity_,\n IFluidLendingFactory lendingFactory_,\n IWETH9 weth_\n ) fToken(liquidity_, lendingFactory_, IERC20(address(weth_))) {}\n\n /// @inheritdoc fToken\n function liquidityCallback(\n address /** token_ */,\n uint256 /** amount_ */,\n bytes calldata /** data_ */\n ) external virtual override(IFToken, fToken) {\n // not needed because msg.value is used directly\n revert FluidLendingError(ErrorTypes.fTokenNativeUnderlying__UnexpectedLiquidityCallback);\n }\n\n receive() external payable {}\n}\n"
|
||
},
|
||
"contracts/protocols/lending/fToken/variables.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ERC20, IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { ERC20Permit } from \"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\";\n\nimport { IAllowanceTransfer } from \"../interfaces/permit2/iAllowanceTransfer.sol\";\nimport { LiquiditySlotsLink } from \"../../../libraries/liquiditySlotsLink.sol\";\nimport { IFToken } from \"../interfaces/iFToken.sol\";\nimport { IAllowanceTransfer } from \"../interfaces/permit2/iAllowanceTransfer.sol\";\nimport { IFluidLendingRewardsRateModel } from \"../interfaces/iLendingRewardsRateModel.sol\";\nimport { IFluidLendingFactory } from \"../interfaces/iLendingFactory.sol\";\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error } from \"../error.sol\";\n\nabstract contract Constants {\n /// @dev permit2 contract, deployed to same address on EVM networks, see https://github.com/Uniswap/permit2\n IAllowanceTransfer internal constant PERMIT2 = IAllowanceTransfer(0x000000000022D473030F116dDEE9F6B43aC78BA3);\n\n /// @dev precision for exchange prices\n uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n /// @dev Ignoring leap years\n uint256 internal constant SECONDS_PER_YEAR = 365 days;\n\n /// @dev max allowed reward rate is 50%\n uint256 internal constant MAX_REWARDS_RATE = 50 * 1e12; // 50%;\n\n /// @dev address of the Liquidity contract.\n IFluidLiquidity internal immutable LIQUIDITY;\n\n /// @dev address of the Lending factory contract.\n IFluidLendingFactory internal immutable LENDING_FACTORY;\n\n /// @dev address of the underlying asset contract.\n IERC20 internal immutable ASSET;\n\n /// @dev number of decimals for the fToken, same as ASSET\n uint8 internal immutable DECIMALS;\n\n /// @dev slot ids in Liquidity contract for underlying token.\n /// Helps in low gas fetch from liquidity contract by skipping delegate call with `readFromStorage`\n bytes32 internal immutable LIQUIDITY_EXCHANGE_PRICES_SLOT;\n bytes32 internal immutable LIQUIDITY_TOTAL_AMOUNTS_SLOT;\n bytes32 internal immutable LIQUIDITY_USER_SUPPLY_SLOT;\n\n /// @param liquidity_ liquidity contract address\n /// @param lendingFactory_ lending factory contract address\n /// @param asset_ underlying token address\n constructor(IFluidLiquidity liquidity_, IFluidLendingFactory lendingFactory_, IERC20 asset_) {\n DECIMALS = IERC20Metadata(address(asset_)).decimals();\n ASSET = asset_;\n LIQUIDITY = liquidity_;\n LENDING_FACTORY = lendingFactory_;\n\n LIQUIDITY_EXCHANGE_PRICES_SLOT = LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT,\n _getLiquiditySlotLinksAsset()\n );\n LIQUIDITY_TOTAL_AMOUNTS_SLOT = LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT,\n _getLiquiditySlotLinksAsset()\n );\n LIQUIDITY_USER_SUPPLY_SLOT = LiquiditySlotsLink.calculateDoubleMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT,\n address(this),\n _getLiquiditySlotLinksAsset()\n );\n }\n\n /// @dev gets asset address for liquidity slot links, extracted to separate method so it can be overridden if needed\n function _getLiquiditySlotLinksAsset() internal view virtual returns (address) {\n return address(ASSET);\n }\n}\n\nabstract contract Variables is ERC20, ERC20Permit, Error, Constants, IFToken {\n /// @dev prefix for token name. fToken will append the underlying asset name\n string private constant TOKEN_NAME_PREFIX = \"Fluid \";\n /// @dev prefix for token symbol. fToken will append the underlying asset symbol\n string private constant TOKEN_SYMBOL_PREFIX = \"f\";\n\n // ------------ storage variables from inherited contracts come before vars here --------\n // _________ ERC20 _______________\n // ----------------------- slot 0 ---------------------------\n // mapping(address => uint256) private _balances;\n\n // ----------------------- slot 1 ---------------------------\n // mapping(address => mapping(address => uint256)) private _allowances;\n\n // ----------------------- slot 2 ---------------------------\n // uint256 private _totalSupply;\n\n // ----------------------- slot 3 ---------------------------\n // string private _name;\n // ----------------------- slot 4 ---------------------------\n // string private _symbol;\n\n // _________ ERC20Permit _______________\n // ----------------------- slot 5 ---------------------------\n // mapping(address => Counters.Counter) private _nonces;\n\n // ----------------------- slot 6 ---------------------------\n // bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n // ----------------------- slot 7 ---------------------------\n /// @dev address of the LendingRewardsRateModel.\n IFluidLendingRewardsRateModel internal _rewardsRateModel;\n\n // -> 12 bytes empty\n uint96 private __placeholder_gap;\n\n // ----------------------- slot 8 ---------------------------\n // optimized to put all storage variables where a SSTORE happens on actions in the same storage slot\n\n /// @dev exchange price for the underlying assset in the liquidity protocol (without rewards)\n uint64 internal _liquidityExchangePrice; // in 1e12 -> (max value 18_446_744,073709551615)\n\n /// @dev exchange price between fToken and the underlying assset (with rewards)\n uint64 internal _tokenExchangePrice; // in 1e12 -> (max value 18_446_744,073709551615)\n\n /// @dev timestamp when exchange prices were updated the last time\n uint40 internal _lastUpdateTimestamp;\n\n /// @dev status for reentrancy guard\n uint8 internal _status;\n\n /// @dev flag to signal if rewards are active without having to read slot 6\n bool internal _rewardsActive;\n\n // 72 bits empty (9 bytes)\n\n // ----------------------- slot 9 ---------------------------\n /// @dev rebalancer address allowed to call `rebalance()` and source for funding rewards (ReserveContract).\n address internal _rebalancer;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n /// @param liquidity_ liquidity contract address\n /// @param lendingFactory_ lending factory contract address\n /// @param asset_ underlying token address\n constructor(\n IFluidLiquidity liquidity_,\n IFluidLendingFactory lendingFactory_,\n IERC20 asset_\n )\n validAddress(address(liquidity_))\n validAddress(address(lendingFactory_))\n validAddress(address(asset_))\n Constants(liquidity_, lendingFactory_, asset_)\n ERC20(\n string(abi.encodePacked(TOKEN_NAME_PREFIX, IERC20Metadata(address(asset_)).name())),\n string(abi.encodePacked(TOKEN_SYMBOL_PREFIX, IERC20Metadata(address(asset_)).symbol()))\n )\n ERC20Permit(string(abi.encodePacked(TOKEN_NAME_PREFIX, IERC20Metadata(address(asset_)).name())))\n {}\n\n /// @dev checks that address is not the zero address, reverts if so. Calling the method in the modifier reduces\n /// bytecode size as modifiers are inlined into bytecode\n function _checkValidAddress(address value_) internal pure {\n if (value_ == address(0)) {\n revert FluidLendingError(ErrorTypes.fToken__InvalidParams);\n }\n }\n\n /// @dev validates that an address is not the zero address\n modifier validAddress(address value_) {\n _checkValidAddress(value_);\n _;\n }\n}\n"
|
||
},
|
||
"contracts/protocols/lending/interfaces/external/iWETH9.sol": {
|
||
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IWETH9 is IERC20 {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n"
|
||
},
|
||
"contracts/protocols/lending/interfaces/iFToken.sol": {
|
||
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\n\nimport { IAllowanceTransfer } from \"./permit2/iAllowanceTransfer.sol\";\nimport { IFluidLendingRewardsRateModel } from \"./iLendingRewardsRateModel.sol\";\nimport { IFluidLendingFactory } from \"./iLendingFactory.sol\";\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\n\ninterface IFTokenAdmin {\n /// @notice updates the rewards rate model contract.\n /// Only callable by LendingFactory auths.\n /// @param rewardsRateModel_ the new rewards rate model contract address.\n /// can be set to address(0) to set no rewards (to save gas)\n function updateRewards(IFluidLendingRewardsRateModel rewardsRateModel_) external;\n\n /// @notice Balances out the difference between fToken supply at Liquidity vs totalAssets().\n /// Deposits underlying from rebalancer address into Liquidity but doesn't mint any shares\n /// -> thus making deposit available as rewards.\n /// Only callable by rebalancer.\n /// @return assets_ amount deposited to Liquidity\n function rebalance() external payable returns (uint256 assets_);\n\n /// @notice gets the liquidity exchange price of the underlying asset, calculates the updated exchange price (with reward rates)\n /// and writes those values to storage.\n /// Callable by anyone.\n /// @return tokenExchangePrice_ exchange price of fToken share to underlying asset\n /// @return liquidityExchangePrice_ exchange price at Liquidity for the underlying asset\n function updateRates() external returns (uint256 tokenExchangePrice_, uint256 liquidityExchangePrice_);\n\n /// @notice sends any potentially stuck funds to Liquidity contract. Only callable by LendingFactory auths.\n function rescueFunds(address token_) external;\n\n /// @notice Updates the rebalancer address (ReserveContract). Only callable by LendingFactory auths.\n function updateRebalancer(address rebalancer_) external;\n}\n\ninterface IFToken is IERC4626, IFTokenAdmin {\n /// @notice returns minimum amount required for deposit (rounded up)\n function minDeposit() external view returns (uint256);\n\n /// @notice returns config, rewards and exchange prices data in a single view method.\n /// @return liquidity_ address of the Liquidity contract.\n /// @return lendingFactory_ address of the Lending factory contract.\n /// @return lendingRewardsRateModel_ address of the rewards rate model contract. changeable by LendingFactory auths.\n /// @return permit2_ address of the Permit2 contract used for deposits / mint with signature\n /// @return rebalancer_ address of the rebalancer allowed to execute `rebalance()`\n /// @return rewardsActive_ true if rewards are currently active\n /// @return liquidityBalance_ current Liquidity supply balance of `address(this)` for the underyling asset\n /// @return liquidityExchangePrice_ (updated) exchange price for the underlying assset in the liquidity protocol (without rewards)\n /// @return tokenExchangePrice_ (updated) exchange price between fToken and the underlying assset (with rewards)\n function getData()\n external\n view\n returns (\n IFluidLiquidity liquidity_,\n IFluidLendingFactory lendingFactory_,\n IFluidLendingRewardsRateModel lendingRewardsRateModel_,\n IAllowanceTransfer permit2_,\n address rebalancer_,\n bool rewardsActive_,\n uint256 liquidityBalance_,\n uint256 liquidityExchangePrice_,\n uint256 tokenExchangePrice_\n );\n\n /// @notice transfers `amount_` of `token_` to liquidity. Only callable by liquidity contract.\n /// @dev this callback is used to optimize gas consumption (reducing necessary token transfers).\n function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external;\n\n /// @notice deposit `assets_` amount with Permit2 signature for underlying asset approval.\n /// reverts with `fToken__MinAmountOut()` if `minAmountOut_` of shares is not reached.\n /// `assets_` must at least be `minDeposit()` amount; reverts otherwise.\n /// @param assets_ amount of assets to deposit\n /// @param receiver_ receiver of minted fToken shares\n /// @param minAmountOut_ minimum accepted amount of shares minted\n /// @param permit_ Permit2 permit message\n /// @param signature_ packed signature of signing the EIP712 hash of `permit_`\n /// @return shares_ amount of minted shares\n function depositWithSignature(\n uint256 assets_,\n address receiver_,\n uint256 minAmountOut_,\n IAllowanceTransfer.PermitSingle calldata permit_,\n bytes calldata signature_\n ) external returns (uint256 shares_);\n\n /// @notice mint amount of `shares_` with Permit2 signature for underlying asset approval.\n /// Signature should approve a little bit more than expected assets amount (`previewMint()`) to avoid reverts.\n /// `shares_` must at least be `minMint()` amount; reverts otherwise.\n /// Note there might be tiny inaccuracies between requested `shares_` and actually received shares amount.\n /// Recommended to use `deposit()` over mint because it is more gas efficient and less likely to revert.\n /// @param shares_ amount of shares to mint\n /// @param receiver_ receiver of minted fToken shares\n /// @param maxAssets_ maximum accepted amount of assets used as input to mint `shares_`\n /// @param permit_ Permit2 permit message\n /// @param signature_ packed signature of signing the EIP712 hash of `permit_`\n /// @return assets_ deposited assets amount\n function mintWithSignature(\n uint256 shares_,\n address receiver_,\n uint256 maxAssets_,\n IAllowanceTransfer.PermitSingle calldata permit_,\n bytes calldata signature_\n ) external returns (uint256 assets_);\n}\n\ninterface IFTokenNativeUnderlying is IFToken {\n /// @notice address that is mapped to the chain native token at Liquidity\n function NATIVE_TOKEN_ADDRESS() external view returns (address);\n\n /// @notice deposits `msg.value` amount of native token for `receiver_`.\n /// `msg.value` must be at least `minDeposit()` amount; reverts otherwise.\n /// Recommended to use `depositNative()` with a `minAmountOut_` param instead to set acceptable limit.\n /// @return shares_ actually minted shares\n function depositNative(address receiver_) external payable returns (uint256 shares_);\n\n /// @notice same as {depositNative} but with an additional setting for minimum output amount.\n /// reverts with `fToken__MinAmountOut()` if `minAmountOut_` of shares is not reached\n function depositNative(address receiver_, uint256 minAmountOut_) external payable returns (uint256 shares_);\n\n /// @notice mints `shares_` for `receiver_`, paying with underlying native token.\n /// `shares_` must at least be `minMint()` amount; reverts otherwise.\n /// `shares_` set to type(uint256).max not supported.\n /// Note there might be tiny inaccuracies between requested `shares_` and actually received shares amount.\n /// Recommended to use `depositNative()` over mint because it is more gas efficient and less likely to revert.\n /// Recommended to use `mintNative()` with a `minAmountOut_` param instead to set acceptable limit.\n /// @return assets_ deposited assets amount\n function mintNative(uint256 shares_, address receiver_) external payable returns (uint256 assets_);\n\n /// @notice same as {mintNative} but with an additional setting for minimum output amount.\n /// reverts with `fToken__MaxAmount()` if `maxAssets_` of assets is surpassed to mint `shares_`.\n function mintNative(\n uint256 shares_,\n address receiver_,\n uint256 maxAssets_\n ) external payable returns (uint256 assets_);\n\n /// @notice withdraws `assets_` amount in native underlying to `receiver_`, burning shares of `owner_`.\n /// If `assets_` equals uint256.max then the whole fToken balance of `owner_` is withdrawn.This does not\n /// consider withdrawal limit at liquidity so best to check with `maxWithdraw()` before.\n /// Note there might be tiny inaccuracies between requested `assets_` and actually received assets amount.\n /// Recommended to use `withdrawNative()` with a `maxSharesBurn_` param instead to set acceptable limit.\n /// @return shares_ burned shares\n function withdrawNative(uint256 assets_, address receiver_, address owner_) external returns (uint256 shares_);\n\n /// @notice same as {withdrawNative} but with an additional setting for minimum output amount.\n /// reverts with `fToken__MaxAmount()` if `maxSharesBurn_` of shares burned is surpassed.\n function withdrawNative(\n uint256 assets_,\n address receiver_,\n address owner_,\n uint256 maxSharesBurn_\n ) external returns (uint256 shares_);\n\n /// @notice redeems `shares_` to native underlying to `receiver_`, burning shares of `owner_`.\n /// If `shares_` equals uint256.max then the whole balance of `owner_` is withdrawn.This does not\n /// consider withdrawal limit at liquidity so best to check with `maxRedeem()` before.\n /// Recommended to use `withdrawNative()` over redeem because it is more gas efficient and can set specific amount.\n /// Recommended to use `redeemNative()` with a `minAmountOut_` param instead to set acceptable limit.\n /// @return assets_ withdrawn assets amount\n function redeemNative(uint256 shares_, address receiver_, address owner_) external returns (uint256 assets_);\n\n /// @notice same as {redeemNative} but with an additional setting for minimum output amount.\n /// reverts with `fToken__MinAmountOut()` if `minAmountOut_` of assets is not reached.\n function redeemNative(\n uint256 shares_,\n address receiver_,\n address owner_,\n uint256 minAmountOut_\n ) external returns (uint256 assets_);\n\n /// @notice withdraw amount of `assets_` in native token with ERC-2612 permit signature for fToken approval.\n /// `owner_` signs ERC-2612 permit `signature_` to give allowance of fTokens to `msg.sender`.\n /// Note there might be tiny inaccuracies between requested `assets_` and actually received assets amount.\n /// allowance via signature should cover `previewWithdraw(assets_)` plus a little buffer to avoid revert.\n /// Inherent trust assumption that `msg.sender` will set `receiver_` and `minAmountOut_` as `owner_` intends\n /// (which is always the case when giving allowance to some spender).\n /// @param sharesToPermit_ shares amount to use for EIP2612 permit(). Should cover `previewWithdraw(assets_)` + small buffer.\n /// @param assets_ amount of assets to withdraw\n /// @param receiver_ receiver of withdrawn assets\n /// @param owner_ owner to withdraw from (must be signature signer)\n /// @param maxSharesBurn_ maximum accepted amount of shares burned\n /// @param deadline_ deadline for signature validity\n /// @param signature_ packed signature of signing the EIP712 hash for ERC-2612 permit\n /// @return shares_ burned shares amount\n function withdrawWithSignatureNative(\n uint256 sharesToPermit_,\n uint256 assets_,\n address receiver_,\n address owner_,\n uint256 maxSharesBurn_,\n uint256 deadline_,\n bytes calldata signature_\n ) external returns (uint256 shares_);\n\n /// @notice redeem amount of `shares_` as native token with ERC-2612 permit signature for fToken approval.\n /// `owner_` signs ERC-2612 permit `signature_` to give allowance of fTokens to `msg.sender`.\n /// Note there might be tiny inaccuracies between requested `shares_` to redeem and actually burned shares.\n /// allowance via signature must cover `shares_` plus a tiny buffer.\n /// Inherent trust assumption that `msg.sender` will set `receiver_` and `minAmountOut_` as `owner_` intends\n /// (which is always the case when giving allowance to some spender).\n /// Recommended to use `withdrawNative()` over redeem because it is more gas efficient and can set specific amount.\n /// @param shares_ amount of shares to redeem\n /// @param receiver_ receiver of withdrawn assets\n /// @param owner_ owner to withdraw from (must be signature signer)\n /// @param minAmountOut_ minimum accepted amount of assets withdrawn\n /// @param deadline_ deadline for signature validity\n /// @param signature_ packed signature of signing the EIP712 hash for ERC-2612 permit\n /// @return assets_ withdrawn assets amount\n function redeemWithSignatureNative(\n uint256 shares_,\n address receiver_,\n address owner_,\n uint256 minAmountOut_,\n uint256 deadline_,\n bytes calldata signature_\n ) external returns (uint256 assets_);\n}\n"
|
||
},
|
||
"contracts/protocols/lending/interfaces/iLendingFactory.sol": {
|
||
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\n\ninterface IFluidLendingFactoryAdmin {\n /// @notice reads if a certain `auth_` address is an allowed auth or not. Owner is auth by default.\n function isAuth(address auth_) external view returns (bool);\n\n /// @notice Sets an address as allowed auth or not. Only callable by owner.\n /// @param auth_ address to set auth value for\n /// @param allowed_ bool flag for whether address is allowed as auth or not\n function setAuth(address auth_, bool allowed_) external;\n\n /// @notice reads if a certain `deployer_` address is an allowed deployer or not. Owner is deployer by default.\n function isDeployer(address deployer_) external view returns (bool);\n\n /// @notice Sets an address as allowed deployer or not. Only callable by owner.\n /// @param deployer_ address to set deployer value for\n /// @param allowed_ bool flag for whether address is allowed as deployer or not\n function setDeployer(address deployer_, bool allowed_) external;\n\n /// @notice Sets the `creationCode_` bytecode for a certain `fTokenType_`. Only callable by auths.\n /// @param fTokenType_ the fToken Type used to refer the creation code\n /// @param creationCode_ contract creation code. can be set to bytes(0) to remove a previously available `fTokenType_`\n function setFTokenCreationCode(string memory fTokenType_, bytes calldata creationCode_) external;\n\n /// @notice creates token for `asset_` for a lending protocol with interest. Only callable by deployers.\n /// @param asset_ address of the asset\n /// @param fTokenType_ type of fToken:\n /// - if it's the native token, it should use `NativeUnderlying`\n /// - otherwise it should use `fToken`\n /// - could be more types available, check `fTokenTypes()`\n /// @param isNativeUnderlying_ flag to signal fToken type that uses native underlying at Liquidity\n /// @return token_ address of the created token\n function createToken(\n address asset_,\n string calldata fTokenType_,\n bool isNativeUnderlying_\n ) external returns (address token_);\n}\n\ninterface IFluidLendingFactory is IFluidLendingFactoryAdmin {\n /// @notice list of all created tokens\n function allTokens() external view returns (address[] memory);\n\n /// @notice list of all fToken types that can be deployed\n function fTokenTypes() external view returns (string[] memory);\n\n /// @notice returns the creation code for a certain `fTokenType_`\n function fTokenCreationCode(string memory fTokenType_) external view returns (bytes memory);\n\n /// @notice address of the Liquidity contract.\n function LIQUIDITY() external view returns (IFluidLiquidity);\n\n /// @notice computes deterministic token address for `asset_` for a lending protocol\n /// @param asset_ address of the asset\n /// @param fTokenType_ type of fToken:\n /// - if it's the native token, it should use `NativeUnderlying`\n /// - otherwise it should use `fToken`\n /// - could be more types available, check `fTokenTypes()`\n /// @return token_ detemrinistic address of the computed token\n function computeToken(address asset_, string calldata fTokenType_) external view returns (address token_);\n}\n"
|
||
},
|
||
"contracts/protocols/lending/interfaces/iLendingRewardsRateModel.sol": {
|
||
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IFluidLendingRewardsRateModel {\n /// @notice Calculates the current rewards rate (APR)\n /// @param totalAssets_ amount of assets in the lending\n /// @return rate_ rewards rate percentage per year with 1e12 RATE_PRECISION, e.g. 1e12 = 1%, 1e14 = 100%\n /// @return ended_ flag to signal that rewards have ended (always 0 going forward)\n /// @return startTime_ start time of rewards to compare against last update timestamp\n function getRate(uint256 totalAssets_) external view returns (uint256 rate_, bool ended_, uint256 startTime_);\n\n /// @notice Returns config constants for rewards rate model\n function getConfig()\n external\n view\n returns (\n uint256 duration_,\n uint256 startTime_,\n uint256 endTime_,\n uint256 startTvl_,\n uint256 maxRate_,\n uint256 rewardAmount_,\n address initiator_\n );\n}\n"
|
||
},
|
||
"contracts/protocols/lending/interfaces/iStakingRewards.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IFluidLendingStakingRewards {\n // Views\n function lastTimeRewardApplicable() external view returns (uint256);\n\n function rewardPerToken() external view returns (uint256);\n\n function earned(address account) external view returns (uint256);\n\n function getRewardForDuration() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n function periodFinish() external view returns (uint256);\n\n function rewardRate() external view returns (uint256);\n\n function lastUpdateTime() external view returns (uint256);\n\n function rewardPerTokenStored() external view returns (uint256);\n\n function rewardsDuration() external view returns (uint256);\n\n function rewardsToken() external view returns (IERC20);\n\n function stakingToken() external view returns (IERC20);\n\n // Mutative\n\n function stake(uint256 amount) external;\n\n function withdraw(uint256 amount) external;\n\n function getReward() external;\n\n function exit() external;\n}\n"
|
||
},
|
||
"contracts/protocols/lending/interfaces/permit2/iAllowanceTransfer.sol": {
|
||
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\n/// @title AllowanceTransfer\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\n/// @dev Requires user's token approval on the Permit2 contract\n/// from https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol.\n/// Copyright (c) 2022 Uniswap Labs\ninterface IAllowanceTransfer {\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n /// @notice Thrown when an allowance on a token has expired.\n /// @param deadline The timestamp at which the allowed amount is no longer valid\n error AllowanceExpired(uint256 deadline);\n\n /// @notice Thrown when an allowance on a token has been depleted.\n /// @param amount The maximum amount allowed\n error InsufficientAllowance(uint256 amount);\n\n /// @notice Thrown when too many nonces are invalidated.\n error ExcessiveInvalidation();\n\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\n event NonceInvalidation(\n address indexed owner,\n address indexed token,\n address indexed spender,\n uint48 newNonce,\n uint48 oldNonce\n );\n\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\n event Approval(\n address indexed owner,\n address indexed token,\n address indexed spender,\n uint160 amount,\n uint48 expiration\n );\n\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\n event Permit(\n address indexed owner,\n address indexed token,\n address indexed spender,\n uint160 amount,\n uint48 expiration,\n uint48 nonce\n );\n\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\n event Lockdown(address indexed owner, address token, address spender);\n\n /// @notice The permit data for a token\n struct PermitDetails {\n // ERC20 token address\n address token;\n // the maximum amount allowed to spend\n uint160 amount;\n // timestamp at which a spender's token allowances become invalid\n uint48 expiration;\n // an incrementing value indexed per owner,token,and spender for each signature\n uint48 nonce;\n }\n\n /// @notice The permit message signed for a single token allownce\n struct PermitSingle {\n // the permit data for a single token alownce\n PermitDetails details;\n // address permissioned on the allowed tokens\n address spender;\n // deadline on the permit signature\n uint256 sigDeadline;\n }\n\n /// @notice The permit message signed for multiple token allowances\n struct PermitBatch {\n // the permit data for multiple token allowances\n PermitDetails[] details;\n // address permissioned on the allowed tokens\n address spender;\n // deadline on the permit signature\n uint256 sigDeadline;\n }\n\n /// @notice The saved permissions\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\n struct PackedAllowance {\n // amount allowed\n uint160 amount;\n // permission expiry\n uint48 expiration;\n // an incrementing value indexed per owner,token,and spender for each signature\n uint48 nonce;\n }\n\n /// @notice A token spender pair.\n struct TokenSpenderPair {\n // the token the spender is approved\n address token;\n // the spender address\n address spender;\n }\n\n /// @notice Details for a token transfer.\n struct AllowanceTransferDetails {\n // the owner of the token\n address from;\n // the recipient of the token\n address to;\n // the amount of the token\n uint160 amount;\n // the token to be transferred\n address token;\n }\n\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\n function allowance(\n address user,\n address token,\n address spender\n ) external view returns (uint160 amount, uint48 expiration, uint48 nonce);\n\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\n /// @param token The token to approve\n /// @param spender The spender address to approve\n /// @param amount The approved amount of the token\n /// @param expiration The timestamp at which the approval is no longer valid\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\n\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\n /// @param owner The owner of the tokens being approved\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\n /// @param signature The owner's signature over the permit data\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\n\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\n /// @param owner The owner of the tokens being approved\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\n /// @param signature The owner's signature over the permit data\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\n\n /// @notice Transfer approved tokens from one address to another\n /// @param from The address to transfer from\n /// @param to The address of the recipient\n /// @param amount The amount of the token to transfer\n /// @param token The token address to transfer\n /// @dev Requires the from address to have approved at least the desired amount\n /// of tokens to msg.sender.\n function transferFrom(address from, address to, uint160 amount, address token) external;\n\n /// @notice Transfer approved tokens in a batch\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\n /// @dev Requires the from addresses to have approved at least the desired amount\n /// of tokens to msg.sender.\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\n\n /// @notice Enables performing a \"lockdown\" of the sender's Permit2 identity\n /// by batch revoking approvals\n /// @param approvals Array of approvals to revoke.\n function lockdown(TokenSpenderPair[] calldata approvals) external;\n\n /// @notice Invalidate nonces for a given (token, spender) pair\n /// @param token The token to invalidate nonces for\n /// @param spender The spender to invalidate nonces for\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\n}\n"
|
||
},
|
||
"contracts/protocols/lending/lendingFactory/events.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLendingFactory } from \"../interfaces/iLendingFactory.sol\";\n\nabstract contract Events {\n /// @notice emitted when a new fToken is created\n event LogTokenCreated(address indexed token, address indexed asset, uint256 indexed count, string fTokenType);\n\n /// @notice emitted when an auth is modified by owner\n event LogSetAuth(address indexed auth, bool indexed allowed);\n\n /// @notice emitted when a deployer is modified by owner\n event LogSetDeployer(address indexed deployer, bool indexed allowed);\n\n /// @notice emitted when the creation code for an fTokenType is set\n event LogSetFTokenCreationCode(string indexed fTokenType, address indexed creationCodePointer);\n}\n"
|
||
},
|
||
"contracts/protocols/lending/lendingFactory/main.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { CREATE3 } from \"solmate/src/utils/CREATE3.sol\";\nimport { SSTORE2 } from \"solmate/src/utils/SSTORE2.sol\";\nimport { Owned } from \"solmate/src/auth/Owned.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\nimport { IFluidLendingFactory, IFluidLendingFactoryAdmin } from \"../interfaces/iLendingFactory.sol\";\nimport { LiquiditySlotsLink } from \"../../../libraries/liquiditySlotsLink.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error } from \"../error.sol\";\nimport { Events } from \"./events.sol\";\n\nabstract contract LendingFactoryVariables is Owned, Error, IFluidLendingFactory {\n /*//////////////////////////////////////////////////////////////\n CONSTANTS / IMMUTABLES\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc IFluidLendingFactory\n IFluidLiquidity public immutable LIQUIDITY;\n\n /// @dev address that is mapped to the chain native token\n address internal constant _NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /*//////////////////////////////////////////////////////////////\n STORAGE VARIABLES\n //////////////////////////////////////////////////////////////*/\n\n // ------------ storage variables from inherited contracts (Owned) come before vars here --------\n\n // ----------------------- slot 0 ---------------------------\n // address public owner;\n\n // 12 bytes empty\n\n // ----------------------- slot 1 ---------------------------\n /// @dev auths can update rewards related config at created fToken contracts.\n /// owner can add/remove auths.\n /// Owner is auth by default.\n mapping(address => uint256) internal _auths;\n\n // ----------------------- slot 2 ---------------------------\n /// @dev deployers can deploy new fTokens.\n /// owner can add/remove deployers.\n /// Owner is deployer by default.\n mapping(address => uint256) internal _deployers;\n\n // ----------------------- slot 3 ---------------------------\n /// @dev list of all created tokens.\n /// Solidity creates an automatic getter only to fetch at a certain position, so explicitly define a getter that returns all.\n address[] internal _allTokens;\n\n // ----------------------- slot 4 ---------------------------\n\n /// @dev available fTokenTypes for deployment. At least EIP2612Deposits, Permit2Deposits, NativeUnderlying.\n /// Solidity creates an automatic getter only to fetch at a certain position, so explicitly define a getter that returns all.\n string[] internal _fTokenTypes;\n\n // ----------------------- slot 5 ---------------------------\n\n /// @dev fToken creation code for each fTokenType, accessed via SSTORE2.\n /// maps keccak256(abi.encode(fTokenType)) -> SSTORE2 written creation code for the fToken contract\n mapping(bytes32 => address) internal _fTokenCreationCodePointers;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(IFluidLiquidity liquidity_, address owner_) Owned(owner_) {\n if (owner_ == address(0)) {\n // Owned does not have a zero check for owner_\n revert FluidLendingError(ErrorTypes.LendingFactory__ZeroAddress);\n }\n\n LIQUIDITY = liquidity_;\n }\n\n /// @inheritdoc IFluidLendingFactory\n function allTokens() public view returns (address[] memory) {\n return _allTokens;\n }\n\n /// @inheritdoc IFluidLendingFactory\n function fTokenTypes() public view returns (string[] memory) {\n return _fTokenTypes;\n }\n\n /// @inheritdoc IFluidLendingFactory\n function fTokenCreationCode(string memory fTokenType_) public view returns (bytes memory) {\n address creationCodePointer_ = _fTokenCreationCodePointers[keccak256(abi.encode(fTokenType_))];\n return creationCodePointer_ == address(0) ? new bytes(0) : SSTORE2.read(creationCodePointer_);\n }\n}\n\nabstract contract LendingFactoryAdmin is LendingFactoryVariables, Events {\n /// @dev validates that an address is not the zero address\n modifier validAddress(address value_) {\n if (value_ == address(0)) {\n revert FluidLendingError(ErrorTypes.LendingFactory__ZeroAddress);\n }\n _;\n }\n\n /// @dev validates that msg.sender is auth or owner\n modifier onlyAuths() {\n if (!isAuth(msg.sender)) {\n revert FluidLendingError(ErrorTypes.LendingFactory__Unauthorized);\n }\n _;\n }\n\n /// @dev validates that msg.sender is deployer or owner\n modifier onlyDeployers() {\n if (!isDeployer(msg.sender)) {\n revert FluidLendingError(ErrorTypes.LendingFactory__Unauthorized);\n }\n _;\n }\n\n /// @inheritdoc IFluidLendingFactoryAdmin\n function isAuth(address auth_) public view returns (bool) {\n return auth_ == owner || _auths[auth_] == 1;\n }\n\n /// @inheritdoc IFluidLendingFactoryAdmin\n function isDeployer(address deployer_) public view returns (bool) {\n return deployer_ == owner || _deployers[deployer_] == 1;\n }\n\n /// @inheritdoc IFluidLendingFactoryAdmin\n function setAuth(address auth_, bool allowed_) external onlyOwner validAddress(auth_) {\n _auths[auth_] = allowed_ ? 1 : 0;\n\n emit LogSetAuth(auth_, allowed_);\n }\n\n /// @inheritdoc IFluidLendingFactoryAdmin\n function setDeployer(address deployer_, bool allowed_) external onlyOwner validAddress(deployer_) {\n _deployers[deployer_] = allowed_ ? 1 : 0;\n\n emit LogSetDeployer(deployer_, allowed_);\n }\n\n /// @inheritdoc IFluidLendingFactoryAdmin\n function setFTokenCreationCode(string memory fTokenType_, bytes calldata creationCode_) external onlyAuths {\n uint256 length_ = _fTokenTypes.length;\n bytes32 fTokenTypeHash_ = keccak256(abi.encode(fTokenType_));\n\n if (creationCode_.length == 0) {\n // remove any previously stored creation code for `fTokenType_`\n delete _fTokenCreationCodePointers[keccak256(abi.encode(fTokenType_))];\n\n // remove key from array _fTokenTypes. _fTokenTypes is most likely an array of very few elements,\n // where setFTokenCreationCode is a rarely called method and the removal of an fTokenType is even more rare.\n // So gas cost is not really an issue here but even if it were, this should still be cheaper than having\n // an additional mapping like with an OpenZeppelin EnumerableSet\n for (uint256 i; i < length_; ++i) {\n if (keccak256(abi.encode(_fTokenTypes[i])) == fTokenTypeHash_) {\n _fTokenTypes[i] = _fTokenTypes[length_ - 1];\n _fTokenTypes.pop();\n break;\n }\n }\n\n emit LogSetFTokenCreationCode(fTokenType_, address(0));\n } else {\n // write creation code to SSTORE2 pointer and set in mapping\n address creationCodePointer_ = SSTORE2.write(creationCode_);\n _fTokenCreationCodePointers[keccak256(abi.encode(fTokenType_))] = creationCodePointer_;\n\n // make sure `fTokenType_` is present in array _fTokenTypes\n bool isPresent_;\n for (uint256 i; i < length_; ++i) {\n if (keccak256(abi.encode(_fTokenTypes[i])) == fTokenTypeHash_) {\n isPresent_ = true;\n break;\n }\n }\n if (!isPresent_) {\n _fTokenTypes.push(fTokenType_);\n }\n\n emit LogSetFTokenCreationCode(fTokenType_, creationCodePointer_);\n }\n }\n\n /// @inheritdoc IFluidLendingFactoryAdmin\n function createToken(\n address asset_,\n string calldata fTokenType_,\n bool isNativeUnderlying_\n ) external validAddress(asset_) onlyDeployers returns (address token_) {\n address creationCodePointer_ = _fTokenCreationCodePointers[keccak256(abi.encode(fTokenType_))];\n if (creationCodePointer_ == address(0)) {\n revert FluidLendingError(ErrorTypes.LendingFactory__InvalidParams);\n }\n\n bytes32 salt_ = _getSalt(asset_, fTokenType_);\n\n if (Address.isContract(CREATE3.getDeployed(salt_))) {\n // revert if token already exists (Solmate CREATE3 does not check before deploying)\n revert FluidLendingError(ErrorTypes.LendingFactory__TokenExists);\n }\n\n bytes32 liquidityExchangePricesSlot_ = LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT,\n // native underlying always uses the native token at Liquidity, but also supports WETH\n isNativeUnderlying_ ? _NATIVE_TOKEN_ADDRESS : asset_\n );\n if (LIQUIDITY.readFromStorage(liquidityExchangePricesSlot_) == 0) {\n // revert if fToken has not been configured at Liquidity contract yet (exchange prices config)\n revert FluidLendingError(ErrorTypes.LendingFactory__LiquidityNotConfigured);\n }\n\n // Use CREATE3 for deterministic deployments. Unfortunately it has 55k gas overhead\n token_ = CREATE3.deploy(\n salt_,\n abi.encodePacked(\n SSTORE2.read(creationCodePointer_), // creation code\n abi.encode(LIQUIDITY, address(this), asset_) // constructor params\n ),\n 0\n );\n\n // Add the created token to the allTokens array\n _allTokens.push(token_);\n\n // Emit the TokenCreated event\n emit LogTokenCreated(token_, asset_, _allTokens.length, fTokenType_);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL\n //////////////////////////////////////////////////////////////*/\n\n /// @dev gets the CREATE3 salt for `asset_` and `fTokenType_`\n function _getSalt(address asset_, string calldata fTokenType_) internal pure returns (bytes32) {\n return keccak256(abi.encode(asset_, fTokenType_));\n }\n}\n\n/// @title Fluid LendingFactory\n/// @notice creates Fluid lending protocol fTokens, which are interacting with Fluid Liquidity.\n/// fTokens are ERC20 & ERC4626 compatible tokens that allow to deposit to Fluid Liquidity to earn interest.\n/// Tokens are created at a deterministic address (see `computeToken()`), only executable by allow-listed auths.\n/// @dev Note the deployed token starts 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 fToken creation codes for future new fToken types.\ncontract FluidLendingFactory is LendingFactoryVariables, LendingFactoryAdmin {\n /// @notice initialize liquidity contract address & owner\n constructor(\n IFluidLiquidity liquidity_,\n address owner_\n ) validAddress(address(liquidity_)) validAddress(owner) LendingFactoryVariables(liquidity_, owner_) {}\n\n /// @inheritdoc IFluidLendingFactory\n function computeToken(address asset_, string calldata fTokenType_) public view returns (address token_) {\n return CREATE3.getDeployed(_getSalt(asset_, fTokenType_));\n }\n}\n"
|
||
},
|
||
"contracts/protocols/lending/lendingRewardsRateModel/main.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLendingRewardsRateModel } from \"../interfaces/iLendingRewardsRateModel.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error } from \"../error.sol\";\n\n/// @title LendingRewardsRateModel\n/// @notice Calculates rewards rate used for an fToken based on a rewardAmount over a given duration. \n/// Rewards start once the allowed initiator address triggers `start()` and only accrue above a certain startTVL.\n/// Max rate cap is at 50%.\ncontract FluidLendingRewardsRateModel is IFluidLendingRewardsRateModel, Error {\n /// @notice Emitted when rewards are started\n event LogRewardsStarted(uint256 startTime, uint256 endTime);\n\n /// @dev precision decimals for rewards rate\n uint256 internal constant RATE_PRECISION = 1e12;\n\n uint256 internal constant SECONDS_PER_YEAR = 365 days;\n\n /// @dev maximum rewards rate is 50%. no config higher than this should be possible.\n uint256 internal constant MAX_RATE = 50 * RATE_PRECISION; // 1e12 = 1%, this is 50%.\n\n /// @dev tvl below which rewards rate is 0\n uint256 internal immutable START_TVL;\n\n /// @dev for how long rewards should run\n uint256 internal immutable DURATION;\n\n /// @dev annualized reward based on constructor input params (duration, rewardAmount)\n uint256 internal immutable YEARLY_REWARD;\n\n /// @dev total amounts to be distributed. not needed but stored for easier tracking via `getConfig`\n uint256 internal immutable REWARD_AMOUNT;\n\n /// @dev address which has access to call start() which kickstarts the rewards\n address internal immutable INITIATOR;\n\n /// @dev when rewards got started\n uint96 internal startTime;\n /// @dev when rewards will get over\n uint96 internal endTime;\n\n /// @dev Validates that an address is not the zero address\n modifier validAddress(address value_) {\n if (value_ == address(0)) {\n revert FluidLendingError(ErrorTypes.LendingRewardsRateModel__ZeroAddress);\n }\n _;\n }\n\n /// @notice sets immutable vars for rewards rate config based on input params.\n /// @param duration_ for how long rewards should run\n /// @param startTvl_ tvl below which rate is 0\n /// @param rewardAmount_ total amount of underlying asset to be distributed as rewards\n /// @param initiator_ address which has access to kickstart the rewards\n constructor(uint256 duration_, uint256 startTvl_, uint256 rewardAmount_, address initiator_) validAddress(initiator_) {\n // sanity checks\n if (duration_ == 0 || rewardAmount_ == 0 || startTvl_ == 0) {\n revert FluidLendingError(ErrorTypes.LendingRewardsRateModel__InvalidParams);\n }\n\n START_TVL = startTvl_;\n DURATION = duration_;\n REWARD_AMOUNT = rewardAmount_;\n INITIATOR = initiator_;\n\n YEARLY_REWARD = (rewardAmount_ * SECONDS_PER_YEAR) / DURATION;\n }\n\n /// @inheritdoc IFluidLendingRewardsRateModel\n function getConfig()\n external\n view\n returns (\n uint256 duration_,\n uint256 startTime_,\n uint256 endTime_,\n uint256 startTvl_,\n uint256 maxRate_,\n uint256 rewardAmount_,\n address initiator_\n )\n {\n return (DURATION, startTime, endTime, START_TVL, MAX_RATE, REWARD_AMOUNT, INITIATOR);\n }\n\n /// @inheritdoc IFluidLendingRewardsRateModel\n function getRate(uint256 totalAssets_) public view returns (uint256 rate_, bool ended_, uint256 startTime_) {\n startTime_ = startTime;\n uint endTime_ = endTime;\n if (startTime_ == 0 || endTime_ == 0) {\n return (0, false, startTime_);\n }\n if (block.timestamp > endTime_) {\n return (0, true, startTime_);\n }\n if (block.timestamp < startTime_) {\n return (0, false, startTime_);\n }\n if (totalAssets_ < START_TVL) {\n return (0, false, startTime_);\n }\n\n rate_ = (YEARLY_REWARD * 1e14) / totalAssets_;\n\n return (rate_ > MAX_RATE ? MAX_RATE : rate_, false, startTime_);\n }\n\n function start() external {\n if (msg.sender != INITIATOR) {\n revert FluidLendingError(ErrorTypes.LendingRewardsRateModel__NotTheInitiator);\n }\n if (startTime > 0 || endTime > 0) {\n revert FluidLendingError(ErrorTypes.LendingRewardsRateModel__AlreadyStarted);\n }\n startTime = uint96(block.timestamp);\n endTime = uint96(block.timestamp + DURATION);\n\n emit LogRewardsStarted(startTime, endTime);\n }\n\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 /***********************************|\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 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/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 liquidityTotalSupplySlot;\n bytes32 liquidityTotalBorrowSlot;\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/reserve/error.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Error {\n error FluidReserveContractError(uint256 errorId_);\n}\n"
|
||
},
|
||
"contracts/reserve/errorTypes.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | Reserve | \n |__________________________________*/\n\n /// @notice thrown when an unauthorized caller is trying to execute an auth-protected method\n uint256 internal constant ReserveContract__Unauthorized = 90001;\n\n /// @notice thrown when an input address is zero\n uint256 internal constant ReserveContract__AddressZero = 90002;\n\n /// @notice thrown when input arrays has different lenghts\n uint256 internal constant ReserveContract__InvalidInputLenghts = 90003;\n\n /// @notice thrown when renounceOwnership is called\n uint256 internal constant ReserveContract__RenounceOwnershipUnsupported = 90004;\n}\n"
|
||
},
|
||
"contracts/reserve/events.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Events {\n /// @notice Emitted when an address is added or removed from the auths\n event LogUpdateAuth(address indexed auth, bool isAuth);\n\n /// @notice Emitted when an address is added or removed from the rebalancers\n event LogUpdateRebalancer(address indexed rebalancer, bool isRebalancer);\n\n /// @notice Emitted when a token is approved for use by a protocol\n event LogAllow(address indexed protocol, address indexed token, uint256 newAllowance, uint existingAllowance);\n\n /// @notice Emitted when a token is revoked for use by a protocol\n event LogRevoke(address indexed protocol, address indexed token);\n\n /// @notice Emitted when fToken is rebalanced\n event LogRebalanceFToken(address indexed protocol, uint amount);\n\n /// @notice Emitted when vault is rebalanced\n event LogRebalanceVault(address indexed protocol, int colAmount, int debtAmount);\n\n /// @notice Emitted whenever funds for a certain `token` are transfered to Liquidity\n event LogTransferFunds(address indexed token);\n}\n"
|
||
},
|
||
"contracts/reserve/main.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { UUPSUpgradeable } from \"@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\nimport { IFluidLiquidity } from \"../liquidity/interfaces/iLiquidity.sol\";\nimport { IFluidLendingFactory } from \"../protocols/lending/interfaces/iLendingFactory.sol\";\nimport { IFTokenAdmin } from \"../protocols/lending/interfaces/iFToken.sol\";\nimport { IFluidVaultT1 } from \"../protocols/vault/interfaces/iVaultT1.sol\";\nimport { SafeTransfer } from \"../libraries/safeTransfer.sol\";\n\nimport { Variables } from \"./variables.sol\";\nimport { Events } from \"./events.sol\";\nimport { ErrorTypes } from \"./errorTypes.sol\";\nimport { Error } from \"./error.sol\";\n\nabstract contract ReserveContractAuth is Variables, Error, Events {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n /// @dev validates that an address is not the zero address\n modifier validAddress(address value_) {\n if (value_ == address(0)) {\n revert FluidReserveContractError(ErrorTypes.ReserveContract__AddressZero);\n }\n _;\n }\n\n /// @notice Checks that the sender is an auth\n modifier onlyAuth() {\n if (!isAuth[msg.sender] && owner() != msg.sender)\n revert FluidReserveContractError(ErrorTypes.ReserveContract__Unauthorized);\n _;\n }\n\n /// @notice Updates an auth's status as an auth\n /// @param auth_ The address to update\n /// @param isAuth_ Whether or not the address should be an auth\n function updateAuth(address auth_, bool isAuth_) external onlyOwner validAddress(auth_) {\n isAuth[auth_] = isAuth_;\n emit LogUpdateAuth(auth_, isAuth_);\n }\n\n /// @notice Updates a rebalancer's status as a rebalancer\n /// @param rebalancer_ The address to update\n /// @param isRebalancer_ Whether or not the address should be a rebalancer\n function updateRebalancer(address rebalancer_, bool isRebalancer_) external onlyAuth validAddress(rebalancer_) {\n isRebalancer[rebalancer_] = isRebalancer_;\n emit LogUpdateRebalancer(rebalancer_, isRebalancer_);\n }\n\n /// @notice Approves protocols to spend the reserves tokens\n /// @dev The parameters are parallel arrays\n /// @param protocols_ The protocols that will be spending reserve tokens\n /// @param tokens_ The tokens to approve\n /// @param amounts_ The amounts to approve\n function approve(\n address[] memory protocols_,\n address[] memory tokens_,\n uint256[] memory amounts_\n ) external onlyAuth {\n if (protocols_.length != tokens_.length || tokens_.length != amounts_.length) {\n revert FluidReserveContractError(ErrorTypes.ReserveContract__InvalidInputLenghts);\n }\n\n for (uint256 i = 0; i < protocols_.length; i++) {\n address protocol_ = protocols_[i];\n address token_ = tokens_[i];\n uint256 amount_ = amounts_[i];\n uint256 existingAllowance_ = IERC20(token_).allowance(address(this), protocol_);\n\n // making approval 0 first and then re-approving with a new amount.\n SafeERC20.safeApprove(IERC20(address(token_)), protocol_, 0);\n SafeERC20.safeApprove(IERC20(address(token_)), protocol_, amount_);\n _protocolTokens[protocol_].add(token_);\n emit LogAllow(protocol_, token_, amount_, existingAllowance_);\n }\n }\n\n /// @notice Revokes protocols' ability to spend the reserves tokens\n /// @dev The parameters are parallel arrays\n /// @param protocols_ The protocols that will no longer be spending reserve tokens\n /// @param tokens_ The tokens to revoke\n function revoke(address[] memory protocols_, address[] memory tokens_) external onlyAuth {\n if (protocols_.length != tokens_.length) {\n revert FluidReserveContractError(ErrorTypes.ReserveContract__InvalidInputLenghts);\n }\n\n for (uint256 i = 0; i < protocols_.length; i++) {\n address protocol_ = protocols_[i];\n address token_ = tokens_[i];\n\n SafeERC20.safeApprove(IERC20(address(token_)), protocol_, 0);\n _protocolTokens[protocol_].remove(token_);\n emit LogRevoke(protocol_, token_);\n }\n }\n}\n\n/// @title Reserve Contract\n/// @notice This contract manages the approval of tokens for use by protocols and\n/// the execution of rebalances on protocols\ncontract FluidReserveContract is Error, ReserveContractAuth, UUPSUpgradeable {\n using EnumerableSet for EnumerableSet.AddressSet;\n using SafeERC20 for IERC20;\n\n /// @notice Checks that the sender is a rebalancer\n modifier onlyRebalancer() {\n if (!isRebalancer[msg.sender]) revert FluidReserveContractError(ErrorTypes.ReserveContract__Unauthorized);\n _;\n }\n\n constructor(IFluidLiquidity liquidity_) validAddress(address(liquidity_)) Variables(liquidity_) {\n // ensure logic contract initializer is not abused by disabling initializing\n // see https://forum.openzeppelin.com/t/security-advisory-initialize-uups-implementation-contracts/15301\n // and https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializing_the_implementation_contract\n _disableInitializers();\n }\n\n /// @notice initializes the contract\n /// @param _auths The addresses that have the auth to approve and revoke protocol token allowances\n /// @param _rebalancers The addresses that can execute a rebalance on a protocol\n /// @param owner_ owner address is able to upgrade contract and update auth users\n function initialize(\n address[] memory _auths,\n address[] memory _rebalancers,\n address owner_\n ) public initializer validAddress(owner_) {\n for (uint256 i = 0; i < _auths.length; i++) {\n isAuth[_auths[i]] = true;\n emit LogUpdateAuth(_auths[i], true);\n }\n for (uint256 i = 0; i < _rebalancers.length; i++) {\n isRebalancer[_rebalancers[i]] = true;\n emit LogUpdateRebalancer(_rebalancers[i], true);\n }\n _transferOwnership(owner_);\n }\n\n function _authorizeUpgrade(address) internal override onlyOwner {}\n\n /// @notice override renounce ownership as it could leave the contract in an unwanted state if called by mistake.\n function renounceOwnership() public view override onlyOwner {\n revert FluidReserveContractError(ErrorTypes.ReserveContract__RenounceOwnershipUnsupported);\n }\n\n /// @notice Executes a rebalance on a protocol by calling that protocol's `rebalance` function\n /// @param protocol_ The protocol to rebalance\n function rebalanceFToken(address protocol_) external onlyRebalancer {\n uint256 amount_ = IFTokenAdmin(protocol_).rebalance();\n emit LogRebalanceFToken(protocol_, amount_);\n }\n\n /// @notice Executes a rebalance on a protocol by calling that protocol's `rebalance` function\n /// @param protocol_ The protocol to rebalance\n function rebalanceVault(address protocol_) external onlyRebalancer {\n (int256 colAmount_, int256 debtAmount_) = IFluidVaultT1(protocol_).rebalance();\n emit LogRebalanceVault(protocol_, colAmount_, debtAmount_);\n }\n\n function transferFunds(address[] calldata tokens_) external virtual onlyAuth {\n for (uint256 i = 0; i < tokens_.length; i++) {\n SafeTransfer.safeTransfer(\n address(tokens_[i]),\n address(LIQUIDITY),\n IERC20(tokens_[i]).balanceOf(address(this))\n );\n emit LogTransferFunds(tokens_[i]);\n }\n }\n\n /// @notice Gets the tokens that are approved for use by a protocol\n /// @param protocol_ The protocol to get the tokens for\n /// @return result_ The tokens that are approved for use by the protocol\n function getProtocolTokens(address protocol_) external view returns (address[] memory result_) {\n EnumerableSet.AddressSet storage tokens_ = _protocolTokens[protocol_];\n result_ = new address[](tokens_.length());\n for (uint256 i = 0; i < tokens_.length(); i++) {\n result_[i] = tokens_.at(i);\n }\n }\n}\n"
|
||
},
|
||
"contracts/reserve/variables.sol": {
|
||
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { OwnableUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { IFluidLiquidity } from \"../liquidity/interfaces/iLiquidity.sol\";\nimport { IFluidLendingFactory } from \"../protocols/lending/interfaces/iLendingFactory.sol\";\n\nabstract contract Constants {\n /// @notice address of the liquidity contract\n IFluidLiquidity public immutable LIQUIDITY;\n\n constructor(IFluidLiquidity liquidity_) {\n LIQUIDITY = liquidity_;\n }\n}\n\nabstract contract Variables is Constants, Initializable, OwnableUpgradeable {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n // ------------ storage variables from inherited contracts (Initializable, OwnableUpgradeable) come before vars here --------\n // @dev variables here start at storage slot 101, before is:\n // - Initializable with storage slot 0:\n // uint8 private _initialized;\n // bool private _initializing;\n // - OwnableUpgradeable with slots 1 to 100:\n // uint256[50] private __gap; (from ContextUpgradeable, slot 1 until slot 50)\n // address private _owner; (at slot 51)\n // uint256[49] private __gap; (slot 52 until slot 100)\n\n // ----------------------- slot 101 ---------------------------\n /// @notice Maps address to there status as an Auth\n mapping(address => bool) public isAuth;\n\n /// @notice Maps address to there status as a Rebalancer\n mapping(address => bool) public isRebalancer;\n\n /// @notice Mapping of protocol addresses to the tokens that are allowed to be used by that protocol\n mapping(address => EnumerableSet.AddressSet) internal _protocolTokens;\n\n constructor(IFluidLiquidity liquidity_) Constants(liquidity_) {}\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"
|
||
},
|
||
"solmate/src/utils/Bytes32AddressLib.sol": {
|
||
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Library for converting between addresses and bytes32 values.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Bytes32AddressLib.sol)\nlibrary Bytes32AddressLib {\n function fromLast20Bytes(bytes32 bytesValue) internal pure returns (address) {\n return address(uint160(uint256(bytesValue)));\n }\n\n function fillLast12Bytes(address addressValue) internal pure returns (bytes32) {\n return bytes32(bytes20(addressValue));\n }\n}\n"
|
||
},
|
||
"solmate/src/utils/CREATE3.sol": {
|
||
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport {Bytes32AddressLib} from \"./Bytes32AddressLib.sol\";\n\n/// @notice Deploy to deterministic addresses without an initcode factor.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/CREATE3.sol)\n/// @author Modified from 0xSequence (https://github.com/0xSequence/create3/blob/master/contracts/Create3.sol)\nlibrary CREATE3 {\n using Bytes32AddressLib for bytes32;\n\n //--------------------------------------------------------------------------------//\n // Opcode | Opcode + Arguments | Description | Stack View //\n //--------------------------------------------------------------------------------//\n // 0x36 | 0x36 | CALLDATASIZE | size //\n // 0x3d | 0x3d | RETURNDATASIZE | 0 size //\n // 0x3d | 0x3d | RETURNDATASIZE | 0 0 size //\n // 0x37 | 0x37 | CALLDATACOPY | //\n // 0x36 | 0x36 | CALLDATASIZE | size //\n // 0x3d | 0x3d | RETURNDATASIZE | 0 size //\n // 0x34 | 0x34 | CALLVALUE | value 0 size //\n // 0xf0 | 0xf0 | CREATE | newContract //\n //--------------------------------------------------------------------------------//\n // Opcode | Opcode + Arguments | Description | Stack View //\n //--------------------------------------------------------------------------------//\n // 0x67 | 0x67XXXXXXXXXXXXXXXX | PUSH8 bytecode | bytecode //\n // 0x3d | 0x3d | RETURNDATASIZE | 0 bytecode //\n // 0x52 | 0x52 | MSTORE | //\n // 0x60 | 0x6008 | PUSH1 08 | 8 //\n // 0x60 | 0x6018 | PUSH1 18 | 24 8 //\n // 0xf3 | 0xf3 | RETURN | //\n //--------------------------------------------------------------------------------//\n bytes internal constant PROXY_BYTECODE = hex\"67_36_3d_3d_37_36_3d_34_f0_3d_52_60_08_60_18_f3\";\n\n bytes32 internal constant PROXY_BYTECODE_HASH = keccak256(PROXY_BYTECODE);\n\n function deploy(\n bytes32 salt,\n bytes memory creationCode,\n uint256 value\n ) internal returns (address deployed) {\n bytes memory proxyChildBytecode = PROXY_BYTECODE;\n\n address proxy;\n /// @solidity memory-safe-assembly\n assembly {\n // Deploy a new contract with our pre-made bytecode via CREATE2.\n // We start 32 bytes into the code to avoid copying the byte length.\n proxy := create2(0, add(proxyChildBytecode, 32), mload(proxyChildBytecode), salt)\n }\n require(proxy != address(0), \"DEPLOYMENT_FAILED\");\n\n deployed = getDeployed(salt);\n (bool success, ) = proxy.call{value: value}(creationCode);\n require(success && deployed.code.length != 0, \"INITIALIZATION_FAILED\");\n }\n\n function getDeployed(bytes32 salt) internal view returns (address) {\n address proxy = keccak256(\n abi.encodePacked(\n // Prefix:\n bytes1(0xFF),\n // Creator:\n address(this),\n // Salt:\n salt,\n // Bytecode hash:\n PROXY_BYTECODE_HASH\n )\n ).fromLast20Bytes();\n\n return\n keccak256(\n abi.encodePacked(\n // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01)\n // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)\n hex\"d6_94\",\n proxy,\n hex\"01\" // Nonce of the proxy contract (1)\n )\n ).fromLast20Bytes();\n }\n}\n"
|
||
},
|
||
"solmate/src/utils/FixedPointMathLib.sol": {
|
||
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Arithmetic library with operations for fixed-point numbers.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)\n/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\nlibrary FixedPointMathLib {\n /*//////////////////////////////////////////////////////////////\n SIMPLIFIED FIXED POINT OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal constant MAX_UINT256 = 2**256 - 1;\n\n uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.\n\n function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.\n }\n\n function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.\n }\n\n function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.\n }\n\n function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.\n }\n\n /*//////////////////////////////////////////////////////////////\n LOW LEVEL FIXED POINT OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n function mulDivDown(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 z) {\n /// @solidity memory-safe-assembly\n assembly {\n // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n revert(0, 0)\n }\n\n // Divide x * y by the denominator.\n z := div(mul(x, y), denominator)\n }\n }\n\n function mulDivUp(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 z) {\n /// @solidity memory-safe-assembly\n assembly {\n // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n revert(0, 0)\n }\n\n // If x * y modulo the denominator is strictly greater than 0,\n // 1 is added to round up the division of x * y by the denominator.\n z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))\n }\n }\n\n function rpow(\n uint256 x,\n uint256 n,\n uint256 scalar\n ) internal pure returns (uint256 z) {\n /// @solidity memory-safe-assembly\n assembly {\n switch x\n case 0 {\n switch n\n case 0 {\n // 0 ** 0 = 1\n z := scalar\n }\n default {\n // 0 ** n = 0\n z := 0\n }\n }\n default {\n switch mod(n, 2)\n case 0 {\n // If n is even, store scalar in z for now.\n z := scalar\n }\n default {\n // If n is odd, store x in z for now.\n z := x\n }\n\n // Shifting right by 1 is like dividing by 2.\n let half := shr(1, scalar)\n\n for {\n // Shift n right by 1 before looping to halve it.\n n := shr(1, n)\n } n {\n // Shift n right by 1 each iteration to halve it.\n n := shr(1, n)\n } {\n // Revert immediately if x ** 2 would overflow.\n // Equivalent to iszero(eq(div(xx, x), x)) here.\n if shr(128, x) {\n revert(0, 0)\n }\n\n // Store x squared.\n let xx := mul(x, x)\n\n // Round to the nearest number.\n let xxRound := add(xx, half)\n\n // Revert if xx + half overflowed.\n if lt(xxRound, xx) {\n revert(0, 0)\n }\n\n // Set x to scaled xxRound.\n x := div(xxRound, scalar)\n\n // If n is even:\n if mod(n, 2) {\n // Compute z * x.\n let zx := mul(z, x)\n\n // If z * x overflowed:\n if iszero(eq(div(zx, x), z)) {\n // Revert if x is non-zero.\n if iszero(iszero(x)) {\n revert(0, 0)\n }\n }\n\n // Round to the nearest number.\n let zxRound := add(zx, half)\n\n // Revert if zx + half overflowed.\n if lt(zxRound, zx) {\n revert(0, 0)\n }\n\n // Return properly scaled zxRound.\n z := div(zxRound, scalar)\n }\n }\n }\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n GENERAL NUMBER UTILITIES\n //////////////////////////////////////////////////////////////*/\n\n function sqrt(uint256 x) internal pure returns (uint256 z) {\n /// @solidity memory-safe-assembly\n assembly {\n let y := x // We start y at x, which will help us make our initial estimate.\n\n z := 181 // The \"correct\" value is 1, but this saves a multiplication later.\n\n // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\n // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\n\n // We check y >= 2^(k + 8) but shift right by k bits\n // each branch to ensure that if x >= 256, then y >= 256.\n if iszero(lt(y, 0x10000000000000000000000000000000000)) {\n y := shr(128, y)\n z := shl(64, z)\n }\n if iszero(lt(y, 0x1000000000000000000)) {\n y := shr(64, y)\n z := shl(32, z)\n }\n if iszero(lt(y, 0x10000000000)) {\n y := shr(32, y)\n z := shl(16, z)\n }\n if iszero(lt(y, 0x1000000)) {\n y := shr(16, y)\n z := shl(8, z)\n }\n\n // Goal was to get z*z*y within a small factor of x. More iterations could\n // get y in a tighter range. Currently, we will have y in [256, 256*2^16).\n // We ensured y >= 256 so that the relative difference between y and y+1 is small.\n // That's not possible if x < 256 but we can just verify those cases exhaustively.\n\n // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.\n // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.\n // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.\n\n // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range\n // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.\n\n // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate\n // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.\n\n // There is no overflow risk here since y < 2^136 after the first branch above.\n z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.\n\n // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\n z := shr(1, add(z, div(x, z)))\n z := shr(1, add(z, div(x, z)))\n z := shr(1, add(z, div(x, z)))\n z := shr(1, add(z, div(x, z)))\n z := shr(1, add(z, div(x, z)))\n z := shr(1, add(z, div(x, z)))\n z := shr(1, add(z, div(x, z)))\n\n // If x+1 is a perfect square, the Babylonian method cycles between\n // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.\n // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\n // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.\n // If you don't care whether the floor or ceil square root is returned, you can remove this statement.\n z := sub(z, lt(div(x, z), z))\n }\n }\n\n function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {\n /// @solidity memory-safe-assembly\n assembly {\n // Mod x by y. Note this will return\n // 0 instead of reverting if y is zero.\n z := mod(x, y)\n }\n }\n\n function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {\n /// @solidity memory-safe-assembly\n assembly {\n // Divide x by y. Note this will return\n // 0 instead of reverting if y is zero.\n r := div(x, y)\n }\n }\n\n function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n /// @solidity memory-safe-assembly\n assembly {\n // Add 1 to x * y if x % y > 0. Note this will\n // return 0 instead of reverting if y is zero.\n z := add(gt(mod(x, y), 0), div(x, y))\n }\n }\n}\n"
|
||
},
|
||
"solmate/src/utils/SSTORE2.sol": {
|
||
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Read and write to persistent storage at a fraction of the cost.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)\n/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)\nlibrary SSTORE2 {\n uint256 internal constant DATA_OFFSET = 1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called.\n\n /*//////////////////////////////////////////////////////////////\n WRITE LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function write(bytes memory data) internal returns (address pointer) {\n // Prefix the bytecode with a STOP opcode to ensure it cannot be called.\n bytes memory runtimeCode = abi.encodePacked(hex\"00\", data);\n\n bytes memory creationCode = abi.encodePacked(\n //---------------------------------------------------------------------------------------------------------------//\n // Opcode | Opcode + Arguments | Description | Stack View //\n //---------------------------------------------------------------------------------------------------------------//\n // 0x60 | 0x600B | PUSH1 11 | codeOffset //\n // 0x59 | 0x59 | MSIZE | 0 codeOffset //\n // 0x81 | 0x81 | DUP2 | codeOffset 0 codeOffset //\n // 0x38 | 0x38 | CODESIZE | codeSize codeOffset 0 codeOffset //\n // 0x03 | 0x03 | SUB | (codeSize - codeOffset) 0 codeOffset //\n // 0x80 | 0x80 | DUP | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset //\n // 0x92 | 0x92 | SWAP3 | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //\n // 0x59 | 0x59 | MSIZE | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //\n // 0x39 | 0x39 | CODECOPY | 0 (codeSize - codeOffset) //\n // 0xf3 | 0xf3 | RETURN | //\n //---------------------------------------------------------------------------------------------------------------//\n hex\"60_0B_59_81_38_03_80_92_59_39_F3\", // Returns all code in the contract except for the first 11 (0B in hex) bytes.\n runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit.\n );\n\n /// @solidity memory-safe-assembly\n assembly {\n // Deploy a new contract with the generated creation code.\n // We start 32 bytes into the code to avoid copying the byte length.\n pointer := create(0, add(creationCode, 32), mload(creationCode))\n }\n\n require(pointer != address(0), \"DEPLOYMENT_FAILED\");\n }\n\n /*//////////////////////////////////////////////////////////////\n READ LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function read(address pointer) internal view returns (bytes memory) {\n return readBytecode(pointer, DATA_OFFSET, pointer.code.length - DATA_OFFSET);\n }\n\n function read(address pointer, uint256 start) internal view returns (bytes memory) {\n start += DATA_OFFSET;\n\n return readBytecode(pointer, start, pointer.code.length - start);\n }\n\n function read(\n address pointer,\n uint256 start,\n uint256 end\n ) internal view returns (bytes memory) {\n start += DATA_OFFSET;\n end += DATA_OFFSET;\n\n require(pointer.code.length >= end, \"OUT_OF_BOUNDS\");\n\n return readBytecode(pointer, start, end - start);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL HELPER LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function readBytecode(\n address pointer,\n uint256 start,\n uint256 size\n ) private view returns (bytes memory data) {\n /// @solidity memory-safe-assembly\n assembly {\n // Get a pointer to some free memory.\n data := mload(0x40)\n\n // Update the free memory pointer to prevent overriding our data.\n // We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)).\n // Adding 31 to size and running the result through the logic above ensures\n // the memory pointer remains word-aligned, following the Solidity convention.\n mstore(0x40, add(data, and(add(add(size, 32), 31), not(31))))\n\n // Store the size of the data in the first 32 byte chunk of free memory.\n mstore(data, size)\n\n // Copy the code into memory right after the 32 bytes we used to store the size.\n extcodecopy(pointer, add(data, 32), start, size)\n }\n }\n}\n"
|
||
}
|
||
},
|
||
"settings": {
|
||
"optimizer": {
|
||
"enabled": true,
|
||
"runs": 10000000
|
||
},
|
||
"evmVersion": "paris",
|
||
"outputSelection": {
|
||
"*": {
|
||
"*": [
|
||
"abi",
|
||
"evm.bytecode",
|
||
"evm.deployedBytecode",
|
||
"evm.methodIdentifiers",
|
||
"metadata",
|
||
"devdoc",
|
||
"userdoc",
|
||
"storageLayout",
|
||
"evm.gasEstimates"
|
||
],
|
||
"": [
|
||
"ast"
|
||
]
|
||
}
|
||
},
|
||
"metadata": {
|
||
"useLiteralContent": true
|
||
}
|
||
}
|
||
} |