{ "language": "Solidity", "sources": { "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.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 * The initial owner is set to the address provided by the deployer. This can\n * 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 Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\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 if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling 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 if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\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" }, "@openzeppelin/contracts/interfaces/draft-IERC6093.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard ERC-20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.\n */\ninterface IERC20Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC20InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC20InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n * @param allowance Amount of tokens a `spender` is allowed to operate with.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC20InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC-721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.\n */\ninterface IERC721Errors {\n /**\n * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.\n * Used in balance queries.\n * @param owner Address of the current owner of a token.\n */\n error ERC721InvalidOwner(address owner);\n\n /**\n * @dev Indicates a `tokenId` whose `owner` is the zero address.\n * @param tokenId Identifier number of a token.\n */\n error ERC721NonexistentToken(uint256 tokenId);\n\n /**\n * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param tokenId Identifier number of a token.\n * @param owner Address of the current owner of a token.\n */\n error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC721InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC721InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param tokenId Identifier number of a token.\n */\n error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC721InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC-1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.\n */\ninterface IERC1155Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n * @param tokenId Identifier number of a token.\n */\n error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC1155InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC1155InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param owner Address of the current owner of a token.\n */\n error ERC1155MissingApprovalForAll(address operator, address owner);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC1155InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC1155InvalidOperator(address operator);\n\n /**\n * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n * Used in batch transfers.\n * @param idsLength Length of the array of token identifiers\n * @param valuesLength Length of the array of token amounts\n */\n error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n" }, "@openzeppelin/contracts/interfaces/IERC1363.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n" }, "@openzeppelin/contracts/interfaces/IERC165.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n" }, "@openzeppelin/contracts/interfaces/IERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n" }, "@openzeppelin/contracts/token/ERC20/ERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC20Metadata} from \"./extensions/IERC20Metadata.sol\";\nimport {Context} from \"../../utils/Context.sol\";\nimport {IERC20Errors} from \"../../interfaces/draft-IERC6093.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 *\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 * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\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 ERC-20\n * applications.\n */\nabstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {\n mapping(address account => uint256) private _balances;\n\n mapping(address account => mapping(address spender => 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 * Both values are immutable: they can only be set once during 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 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 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 default value returned by this function, unless\n * it's 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 returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual 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 `value`.\n */\n function transfer(address to, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `value` 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 value) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Skips emitting an {Approval} event indicating an allowance update. This is not\n * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].\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 `value`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `value`.\n */\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, value);\n _transfer(from, to, value);\n return true;\n }\n\n /**\n * @dev Moves a `value` 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 * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _transfer(address from, address to, uint256 value) internal {\n if (from == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n if (to == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(from, to, value);\n }\n\n /**\n * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n * this function.\n *\n * Emits a {Transfer} event.\n */\n function _update(address from, address to, uint256 value) internal virtual {\n if (from == address(0)) {\n // Overflow check required: The rest of the code assumes that totalSupply never overflows\n _totalSupply += value;\n } else {\n uint256 fromBalance = _balances[from];\n if (fromBalance < value) {\n revert ERC20InsufficientBalance(from, fromBalance, value);\n }\n unchecked {\n // Overflow not possible: value <= fromBalance <= totalSupply.\n _balances[from] = fromBalance - value;\n }\n }\n\n if (to == address(0)) {\n unchecked {\n // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n _totalSupply -= value;\n }\n } else {\n unchecked {\n // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n _balances[to] += value;\n }\n }\n\n emit Transfer(from, to, value);\n }\n\n /**\n * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n * Relies on the `_update` mechanism\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _mint(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(address(0), account, value);\n }\n\n /**\n * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n * Relies on the `_update` mechanism.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead\n */\n function _burn(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n _update(account, address(0), value);\n }\n\n /**\n * @dev Sets `value` 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 * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n */\n function _approve(address owner, address spender, uint256 value) internal {\n _approve(owner, spender, value, true);\n }\n\n /**\n * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n *\n * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n * `Approval` event during `transferFrom` operations.\n *\n * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n * true using the following override:\n *\n * ```solidity\n * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n * super._approve(owner, spender, value, true);\n * }\n * ```\n *\n * Requirements are the same as {_approve}.\n */\n function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n if (owner == address(0)) {\n revert ERC20InvalidApprover(address(0));\n }\n if (spender == address(0)) {\n revert ERC20InvalidSpender(address(0));\n }\n _allowances[owner][spender] = value;\n if (emitEvent) {\n emit Approval(owner, spender, value);\n }\n }\n\n /**\n * @dev Updates `owner`'s allowance for `spender` based on spent `value`.\n *\n * Does not update the allowance value in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Does not emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance < type(uint256).max) {\n if (currentAllowance < value) {\n revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n }\n unchecked {\n _approve(owner, spender, currentAllowance - value, false);\n }\n }\n }\n}\n" }, "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\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 v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\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 value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens as the allowance of `spender` over the\n * 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 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` 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(address from, address to, uint256 value) external returns (bool);\n}\n" }, "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 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 /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` 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 */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\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 * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\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 * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n" }, "@openzeppelin/contracts/utils/Arrays.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)\n// This file was procedurally generated from scripts/generate/templates/Arrays.js.\n\npragma solidity ^0.8.20;\n\nimport {Comparators} from \"./Comparators.sol\";\nimport {SlotDerivation} from \"./SlotDerivation.sol\";\nimport {StorageSlot} from \"./StorageSlot.sol\";\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Collection of functions related to array types.\n */\nlibrary Arrays {\n using SlotDerivation for bytes32;\n using StorageSlot for bytes32;\n\n /**\n * @dev Sort an array of uint256 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n uint256[] memory array,\n function(uint256, uint256) pure returns (bool) comp\n ) internal pure returns (uint256[] memory) {\n _quickSort(_begin(array), _end(array), comp);\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of uint256 in increasing order.\n */\n function sort(uint256[] memory array) internal pure returns (uint256[] memory) {\n sort(array, Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of address (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n address[] memory array,\n function(address, address) pure returns (bool) comp\n ) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of address in increasing order.\n */\n function sort(address[] memory array) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of bytes32 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n bytes32[] memory array,\n function(bytes32, bytes32) pure returns (bool) comp\n ) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.\n */\n function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops\n * at end (exclusive). Sorting follows the `comp` comparator.\n *\n * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.\n *\n * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should\n * be used only if the limits are within a memory array.\n */\n function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {\n unchecked {\n if (end - begin < 0x40) return;\n\n // Use first element as pivot\n uint256 pivot = _mload(begin);\n // Position where the pivot should be at the end of the loop\n uint256 pos = begin;\n\n for (uint256 it = begin + 0x20; it < end; it += 0x20) {\n if (comp(_mload(it), pivot)) {\n // If the value stored at the iterator's position comes before the pivot, we increment the\n // position of the pivot and move the value there.\n pos += 0x20;\n _swap(pos, it);\n }\n }\n\n _swap(begin, pos); // Swap pivot into place\n _quickSort(begin, pos, comp); // Sort the left side of the pivot\n _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first element of `array`.\n */\n function _begin(uint256[] memory array) private pure returns (uint256 ptr) {\n assembly (\"memory-safe\") {\n ptr := add(array, 0x20)\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word\n * that comes just after the last element of the array.\n */\n function _end(uint256[] memory array) private pure returns (uint256 ptr) {\n unchecked {\n return _begin(array) + array.length * 0x20;\n }\n }\n\n /**\n * @dev Load memory word (as a uint256) at location `ptr`.\n */\n function _mload(uint256 ptr) private pure returns (uint256 value) {\n assembly {\n value := mload(ptr)\n }\n }\n\n /**\n * @dev Swaps the elements memory location `ptr1` and `ptr2`.\n */\n function _swap(uint256 ptr1, uint256 ptr2) private pure {\n assembly {\n let value1 := mload(ptr1)\n let value2 := mload(ptr2)\n mstore(ptr1, value2)\n mstore(ptr2, value1)\n }\n }\n\n /// @dev Helper: low level cast address memory array to uint256 memory array\n function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 memory array to uint256 memory array\n function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast address comp function to uint256 comp function\n function _castToUint256Comp(\n function(address, address) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 comp function to uint256 comp function\n function _castToUint256Comp(\n function(bytes32, bytes32) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /**\n * @dev Searches a sorted `array` and returns the first index that contains\n * a value greater or equal to `element`. If no such index exists (i.e. all\n * values in the array are strictly less than `element`), the array length is\n * returned. Time complexity O(log n).\n *\n * NOTE: The `array` is expected to be sorted in ascending order, and to\n * contain no repeated elements.\n *\n * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks\n * support for repeated elements in the array. The {lowerBound} function should\n * be used instead.\n */\n function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.\n if (low > 0 && unsafeAccess(array, low - 1).value == element) {\n return low - 1;\n } else {\n return low;\n }\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value greater or equal than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].\n */\n function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value strictly greater than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].\n */\n function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {lowerBound}, but with an array in memory.\n */\n function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {upperBound}, but with an array in memory.\n */\n function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getAddressSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytes32Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getUint256Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(address[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes32[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(uint256[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/Comparators.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to compare values.\n *\n * _Available since v5.1._\n */\nlibrary Comparators {\n function lt(uint256 a, uint256 b) internal pure returns (bool) {\n return a < b;\n }\n\n function gt(uint256 a, uint256 b) internal pure returns (bool) {\n return a > b;\n }\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\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 function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n" }, "@openzeppelin/contracts/utils/introspection/IERC165.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\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[ERC 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 v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\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 ternary(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 ternary(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 towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / 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 high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\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\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\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²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\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 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n" }, "@openzeppelin/contracts/utils/math/SafeCast.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool 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 */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\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 function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\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 function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\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 function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\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 function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\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 function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\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 function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\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 function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\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 function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\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 function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\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 function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\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 function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\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 function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\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 function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\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 function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\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 function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\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 function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\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 function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\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 function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\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 function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\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 function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\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 function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\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 function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\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 function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\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 function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\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 function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\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 function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\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 function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\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 function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\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 function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\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 function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\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 function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\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 function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\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 function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\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 function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\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 function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\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 function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\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 function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\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 function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\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 function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\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 function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\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 function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\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 function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\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 function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\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 function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\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 function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\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 function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\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 function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\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 function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\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 function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\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 function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\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 function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\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 function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\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 function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\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 function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\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 function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\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 function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\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 function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\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 function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\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 function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\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 function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\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 function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\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 function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\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 function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\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 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 if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/Panic.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/Pausable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n bool private _paused;\n\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n /**\n * @dev The operation failed because the contract is paused.\n */\n error EnforcedPause();\n\n /**\n * @dev The operation failed because the contract is not paused.\n */\n error ExpectedPause();\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n _requireNotPaused();\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n _requirePaused();\n _;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Throws if the contract is paused.\n */\n function _requireNotPaused() internal view virtual {\n if (paused()) {\n revert EnforcedPause();\n }\n }\n\n /**\n * @dev Throws if the contract is not paused.\n */\n function _requirePaused() internal view virtual {\n if (!paused()) {\n revert ExpectedPause();\n }\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" }, "@openzeppelin/contracts/utils/SlotDerivation.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)\n// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots\n * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by\n * the solidity language / compiler.\n *\n * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].\n *\n * Example usage:\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using StorageSlot for bytes32;\n * using SlotDerivation for bytes32;\n *\n * // Declare a namespace\n * string private constant _NAMESPACE = \"\"; // eg. OpenZeppelin.Slot\n *\n * function setValueInNamespace(uint256 key, address newValue) internal {\n * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;\n * }\n *\n * function getValueInNamespace(uint256 key) internal view returns (address) {\n * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {StorageSlot}.\n *\n * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking\n * upgrade safety will ignore the slots accessed through this library.\n *\n * _Available since v5.1._\n */\nlibrary SlotDerivation {\n /**\n * @dev Derive an ERC-7201 slot from a string (namespace).\n */\n function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {\n assembly (\"memory-safe\") {\n mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))\n slot := and(keccak256(0x00, 0x20), not(0xff))\n }\n }\n\n /**\n * @dev Add an offset to a slot to get the n-th element of a structure or an array.\n */\n function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {\n unchecked {\n return bytes32(uint256(slot) + pos);\n }\n }\n\n /**\n * @dev Derive the location of the first element in an array from the slot where the length is stored.\n */\n function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, slot)\n result := keccak256(0x00, 0x20)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, and(key, shr(96, not(0))))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, iszero(iszero(key)))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/StorageSlot.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\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 ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\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(newImplementation.code.length > 0);\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\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 struct Int256Slot {\n int256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes 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 assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n */\n function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\nimport {Arrays} from \"../Arrays.sol\";\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 * - Set can be cleared (all elements removed) in O(n).\n *\n * ```solidity\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 is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value => uint256) _positions;\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._positions[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 cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 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 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function _clear(Set storage set) private {\n uint256 len = _length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\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._positions[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 Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(Bytes32Set storage set) internal {\n _clear(set._inner);\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 assembly (\"memory-safe\") {\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 Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(AddressSet storage set) internal {\n _clear(set._inner);\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 assembly (\"memory-safe\") {\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 Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(UintSet storage set) internal {\n _clear(set._inner);\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 assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n}\n" }, "contracts/Configuration.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nstruct MarketplaceConfig {\n CollateralConfig collateral;\n ProofConfig proofs;\n SlotReservationsConfig reservations;\n uint64 requestDurationLimit;\n}\n\nstruct CollateralConfig {\n /// @dev percentage of collateral that is used as repair reward\n uint8 repairRewardPercentage;\n uint8 maxNumberOfSlashes; // frees slot when the number of slashing reaches this value\n uint8 slashPercentage; // percentage of the collateral that is slashed\n uint8 validatorRewardPercentage; // percentage of the slashed amount going to the validators\n}\n\nstruct ProofConfig {\n uint64 period; // proofs requirements are calculated per period (in seconds)\n uint64 timeout; // mark proofs as missing before the timeout (in seconds)\n uint8 downtime; // ignore this much recent blocks for proof requirements\n // Ensures the pointer does not remain in downtime for many consecutive\n // periods. For each period increase, move the pointer `pointerProduct`\n // blocks. Should be a prime number to ensure there are no cycles.\n uint8 downtimeProduct;\n string zkeyHash; // hash of the zkey file which is linked to the verifier\n}\n\nstruct SlotReservationsConfig {\n // Number of allowed reservations per slot\n uint8 maxReservations;\n}\n" }, "contracts/Endian.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ncontract Endian {\n /// reverses byte order to allow conversion between little endian and big\n /// endian integers\n function _byteSwap(bytes32 input) internal pure returns (bytes32 output) {\n output = output | bytes1(input);\n for (uint i = 1; i < 32; i++) {\n output = output >> 8;\n output = output | bytes1(input << (i * 8));\n }\n }\n}\n" }, "contracts/FuzzMarketplace.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./TestToken.sol\";\nimport \"./Marketplace.sol\";\nimport \"./TestVerifier.sol\";\n\ncontract FuzzMarketplace is Marketplace {\n constructor()\n Marketplace(\n MarketplaceConfig(\n CollateralConfig(10, 5, 10, 20),\n ProofConfig(10, 5, 64, 67, \"\"),\n SlotReservationsConfig(20),\n 60 * 60 * 24 * 30 // 30 days\n ),\n new TestToken(),\n new TestVerifier()\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n // Properties to be tested through fuzzing\n\n MarketplaceTotals private _lastSeenTotals;\n\n function neverDecreaseTotals() public {\n assert(_marketplaceTotals.received >= _lastSeenTotals.received);\n assert(_marketplaceTotals.sent >= _lastSeenTotals.sent);\n _lastSeenTotals = _marketplaceTotals;\n }\n\n function neverLoseFunds() public view {\n uint256 total = _marketplaceTotals.received - _marketplaceTotals.sent;\n assert(token().balanceOf(address(this)) >= total);\n }\n}\n" }, "contracts/Groth16.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nstruct G1Point {\n uint256 x;\n uint256 y;\n}\n\n// A field element F_{p^2} encoded as `real + i * imag`.\n// We chose to not represent this as an array of 2 numbers, because both Circom\n// and Ethereum EIP-197 encode to an array, but with conflicting encodings.\nstruct Fp2Element {\n uint256 real;\n uint256 imag;\n}\n\nstruct G2Point {\n Fp2Element x;\n Fp2Element y;\n}\n\nstruct Groth16Proof {\n G1Point a;\n G2Point b;\n G1Point c;\n}\n\ninterface IGroth16Verifier {\n function verify(\n Groth16Proof calldata proof,\n uint256[] calldata pubSignals\n ) external view returns (bool);\n}\n" }, "contracts/Groth16Verifier.sol": { "content": "// Copyright 2017 Christian Reitwiessner\n// Copyright 2019 OKIMS\n// Copyright 2024 Codex\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\nimport \"./Groth16.sol\";\n\ncontract Groth16Verifier is IGroth16Verifier {\n uint256 private constant _P =\n 21888242871839275222246405745257275088696311157297823662689037894645226208583;\n uint256 private constant _R =\n 21888242871839275222246405745257275088548364400416034343698204186575808495617;\n\n VerifyingKey private _verifyingKey;\n\n struct VerifyingKey {\n G1Point alpha1;\n G2Point beta2;\n G2Point gamma2;\n G2Point delta2;\n G1Point[] ic;\n }\n\n constructor(VerifyingKey memory key) {\n _verifyingKey.alpha1 = key.alpha1;\n _verifyingKey.beta2 = key.beta2;\n _verifyingKey.gamma2 = key.gamma2;\n _verifyingKey.delta2 = key.delta2;\n for (uint i = 0; i < key.ic.length; i++) {\n _verifyingKey.ic.push(key.ic[i]);\n }\n }\n\n function _negate(G1Point memory point) private pure returns (G1Point memory) {\n return G1Point(point.x, (_P - point.y) % _P);\n }\n\n function _add(\n G1Point memory point1,\n G1Point memory point2\n ) private view returns (bool success, G1Point memory sum) {\n // Call the precompiled contract for addition on the alt_bn128 curve.\n // The call will fail if the points are not valid group elements:\n // https://eips.ethereum.org/EIPS/eip-196#exact-semantics\n\n uint256[4] memory input;\n input[0] = point1.x;\n input[1] = point1.y;\n input[2] = point2.x;\n input[3] = point2.y;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n success := staticcall(gas(), 6, input, 128, sum, 64)\n }\n }\n\n function _multiply(\n G1Point memory point,\n uint256 scalar\n ) private view returns (bool success, G1Point memory product) {\n // Call the precompiled contract for scalar multiplication on the alt_bn128\n // curve. The call will fail if the points are not valid group elements:\n // https://eips.ethereum.org/EIPS/eip-196#exact-semantics\n\n uint256[3] memory input;\n input[0] = point.x;\n input[1] = point.y;\n input[2] = scalar;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n success := staticcall(gas(), 7, input, 96, product, 64)\n }\n }\n\n function _checkPairing(\n G1Point memory a1,\n G2Point memory a2,\n G1Point memory b1,\n G2Point memory b2,\n G1Point memory c1,\n G2Point memory c2,\n G1Point memory d1,\n G2Point memory d2\n ) private view returns (bool success, uint256 outcome) {\n // Call the precompiled contract for pairing check on the alt_bn128 curve.\n // The call will fail if the points are not valid group elements:\n // https://eips.ethereum.org/EIPS/eip-197#specification\n\n uint256[24] memory input; // 4 pairs of G1 and G2 points\n uint256[1] memory output;\n\n input[0] = a1.x;\n input[1] = a1.y;\n input[2] = a2.x.imag;\n input[3] = a2.x.real;\n input[4] = a2.y.imag;\n input[5] = a2.y.real;\n\n input[6] = b1.x;\n input[7] = b1.y;\n input[8] = b2.x.imag;\n input[9] = b2.x.real;\n input[10] = b2.y.imag;\n input[11] = b2.y.real;\n\n input[12] = c1.x;\n input[13] = c1.y;\n input[14] = c2.x.imag;\n input[15] = c2.x.real;\n input[16] = c2.y.imag;\n input[17] = c2.y.real;\n\n input[18] = d1.x;\n input[19] = d1.y;\n input[20] = d2.x.imag;\n input[21] = d2.x.real;\n input[22] = d2.y.imag;\n input[23] = d2.y.real;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n success := staticcall(gas(), 8, input, 768, output, 32)\n }\n return (success, output[0]);\n }\n\n function verify(\n Groth16Proof calldata proof,\n uint256[] memory input\n ) public view returns (bool success) {\n // Check amount of public inputs\n if (input.length + 1 != _verifyingKey.ic.length) {\n return false;\n }\n // Check that public inputs are field elements\n for (uint i = 0; i < input.length; i++) {\n if (input[i] >= _R) {\n return false;\n }\n }\n // Compute the linear combination\n G1Point memory combination = _verifyingKey.ic[0];\n for (uint i = 0; i < input.length; i++) {\n G1Point memory product;\n (success, product) = _multiply(_verifyingKey.ic[i + 1], input[i]);\n if (!success) {\n return false;\n }\n (success, combination) = _add(combination, product);\n if (!success) {\n return false;\n }\n }\n // Check the pairing\n uint256 outcome;\n (success, outcome) = _checkPairing(\n _negate(proof.a),\n proof.b,\n _verifyingKey.alpha1,\n _verifyingKey.beta2,\n combination,\n _verifyingKey.gamma2,\n proof.c,\n _verifyingKey.delta2\n );\n if (!success) {\n return false;\n }\n return outcome == 1;\n }\n}\n" }, "contracts/Marketplace.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"./Configuration.sol\";\nimport \"./Requests.sol\";\nimport \"./Proofs.sol\";\nimport \"./SlotReservations.sol\";\nimport \"./StateRetrieval.sol\";\nimport \"./Endian.sol\";\nimport \"./Groth16.sol\";\n\ncontract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {\n error Marketplace_RepairRewardPercentageTooHigh();\n error Marketplace_SlashPercentageTooHigh();\n error Marketplace_MaximumSlashingTooHigh();\n error Marketplace_InvalidExpiry();\n error Marketplace_InvalidMaxSlotLoss();\n error Marketplace_InsufficientSlots();\n error Marketplace_InsufficientDuration();\n error Marketplace_InsufficientProofProbability();\n error Marketplace_InsufficientCollateral();\n error Marketplace_InsufficientReward();\n error Marketplace_InvalidClientAddress();\n error Marketplace_RequestAlreadyExists();\n error Marketplace_InvalidSlot();\n error Marketplace_InvalidCid();\n error Marketplace_SlotNotFree();\n error Marketplace_InvalidSlotHost();\n error Marketplace_AlreadyPaid();\n error Marketplace_TransferFailed();\n error Marketplace_UnknownRequest();\n error Marketplace_InvalidState();\n error Marketplace_StartNotBeforeExpiry();\n error Marketplace_SlotNotAcceptingProofs();\n error Marketplace_ProofNotSubmittedByHost();\n error Marketplace_SlotIsFree();\n error Marketplace_ReservationRequired();\n error Marketplace_NothingToWithdraw();\n error Marketplace_DurationExceedsLimit();\n\n using EnumerableSet for EnumerableSet.Bytes32Set;\n using EnumerableSet for EnumerableSet.AddressSet;\n using Requests for Request;\n using AskHelpers for Ask;\n\n IERC20 private immutable _token;\n MarketplaceConfig private _config;\n\n mapping(RequestId => Request) private _requests;\n mapping(RequestId => RequestContext) internal _requestContexts;\n mapping(SlotId => Slot) internal _slots;\n\n MarketplaceTotals internal _marketplaceTotals;\n\n struct RequestContext {\n RequestState state;\n /// @notice Tracks how much funds should be returned to the client as not all funds might be used for hosting the request\n /// @dev The sum starts with the full reward amount for the request and is reduced every time a host fills a slot.\n /// The reduction is calculated from the duration of time between the slot being filled and the request's end.\n /// This is the amount that will be paid out to the host when the request successfully finishes.\n /// @dev fundsToReturnToClient == 0 is used to signal that after request is terminated all the remaining funds were withdrawn.\n /// This is possible, because technically it is not possible for this variable to reach 0 in \"natural\" way as\n /// that would require all the slots to be filled at the same block as the request was created.\n uint256 fundsToReturnToClient;\n uint64 slotsFilled;\n uint64 startedAt;\n uint64 endsAt;\n uint64 expiresAt;\n }\n\n struct Slot {\n SlotState state;\n RequestId requestId;\n /// @notice Timestamp that signals when slot was filled\n /// @dev Used for calculating payouts as hosts are paid\n /// based on time they actually host the content\n uint64 filledAt;\n uint64 slotIndex;\n /// @notice Tracks the current amount of host's collateral that is\n /// to be payed out at the end of Slot's lifespan.\n /// @dev When Slot is filled, the collateral is collected in amount\n /// of request.ask.collateralPerByte * request.ask.slotSize\n /// (== request.ask.collateralPerSlot() when using the AskHelpers library)\n /// @dev When Host is slashed for missing a proof the slashed amount is\n /// reflected in this variable\n uint256 currentCollateral;\n /// @notice address used for collateral interactions and identifying hosts\n address host;\n }\n\n struct ActiveSlot {\n Request request;\n uint64 slotIndex;\n }\n\n constructor(\n MarketplaceConfig memory config,\n IERC20 token_,\n IGroth16Verifier verifier\n ) SlotReservations(config.reservations) Proofs(config.proofs, verifier) {\n _token = token_;\n\n if (config.collateral.repairRewardPercentage > 100)\n revert Marketplace_RepairRewardPercentageTooHigh();\n if (config.collateral.slashPercentage > 100)\n revert Marketplace_SlashPercentageTooHigh();\n\n if (\n config.collateral.maxNumberOfSlashes * config.collateral.slashPercentage >\n 100\n ) {\n revert Marketplace_MaximumSlashingTooHigh();\n }\n _config = config;\n }\n\n function configuration() public view returns (MarketplaceConfig memory) {\n return _config;\n }\n\n function token() public view returns (IERC20) {\n return _token;\n }\n\n function currentCollateral(SlotId slotId) public view returns (uint256) {\n return _slots[slotId].currentCollateral;\n }\n\n function requestStorage(Request calldata request) public {\n RequestId id = request.id();\n\n if (request.client != msg.sender) revert Marketplace_InvalidClientAddress();\n if (_requests[id].client != address(0)) {\n revert Marketplace_RequestAlreadyExists();\n }\n if (request.expiry == 0 || request.expiry >= request.ask.duration)\n revert Marketplace_InvalidExpiry();\n if (request.ask.slots == 0) revert Marketplace_InsufficientSlots();\n if (request.ask.maxSlotLoss > request.ask.slots)\n revert Marketplace_InvalidMaxSlotLoss();\n if (request.ask.duration == 0) {\n revert Marketplace_InsufficientDuration();\n }\n if (request.ask.proofProbability == 0) {\n revert Marketplace_InsufficientProofProbability();\n }\n if (request.ask.collateralPerByte == 0) {\n revert Marketplace_InsufficientCollateral();\n }\n if (request.ask.pricePerBytePerSecond == 0) {\n revert Marketplace_InsufficientReward();\n }\n if (bytes(request.content.cid).length == 0) {\n revert Marketplace_InvalidCid();\n }\n if (request.ask.duration > _config.requestDurationLimit) {\n revert Marketplace_DurationExceedsLimit();\n }\n\n _requests[id] = request;\n _requestContexts[id].endsAt =\n uint64(block.timestamp) +\n request.ask.duration;\n _requestContexts[id].expiresAt = uint64(block.timestamp) + request.expiry;\n\n _addToMyRequests(request.client, id);\n\n uint256 amount = request.maxPrice();\n _requestContexts[id].fundsToReturnToClient = amount;\n _marketplaceTotals.received += amount;\n _transferFrom(msg.sender, amount);\n\n emit StorageRequested(id, request.ask, _requestContexts[id].expiresAt);\n }\n\n /**\n * @notice Fills a slot. Reverts if an invalid proof of the slot data is\n provided.\n * @param requestId RequestId identifying the request containing the slot to\n fill.\n * @param slotIndex Index of the slot in the request.\n * @param proof Groth16 proof procing possession of the slot data.\n */\n function fillSlot(\n RequestId requestId,\n uint64 slotIndex,\n Groth16Proof calldata proof\n ) public requestIsKnown(requestId) {\n Request storage request = _requests[requestId];\n if (slotIndex >= request.ask.slots) revert Marketplace_InvalidSlot();\n\n SlotId slotId = Requests.slotId(requestId, slotIndex);\n\n if (!_reservations[slotId].contains(msg.sender))\n revert Marketplace_ReservationRequired();\n\n Slot storage slot = _slots[slotId];\n slot.requestId = requestId;\n slot.slotIndex = slotIndex;\n RequestContext storage context = _requestContexts[requestId];\n\n if (\n slotState(slotId) != SlotState.Free &&\n slotState(slotId) != SlotState.Repair\n ) {\n revert Marketplace_SlotNotFree();\n }\n\n slot.host = msg.sender;\n slot.filledAt = uint64(block.timestamp);\n\n _startRequiringProofs(slotId);\n submitProof(slotId, proof);\n\n context.slotsFilled += 1;\n context.fundsToReturnToClient -= _slotPayout(requestId, slot.filledAt);\n\n // Collect collateral\n uint256 collateralAmount;\n uint256 collateralPerSlot = request.ask.collateralPerSlot();\n if (slotState(slotId) == SlotState.Repair) {\n // Host is repairing a slot and is entitled for repair reward, so he gets \"discounted collateral\"\n // in this way he gets \"physically\" the reward at the end of the request when the full amount of collateral\n // is returned to him.\n collateralAmount =\n collateralPerSlot -\n ((collateralPerSlot * _config.collateral.repairRewardPercentage) / 100);\n } else {\n collateralAmount = collateralPerSlot;\n }\n _transferFrom(msg.sender, collateralAmount);\n _marketplaceTotals.received += collateralAmount;\n slot.currentCollateral = collateralPerSlot; // Even if he has collateral discounted, he is operating with full collateral\n\n _addToMySlots(slot.host, slotId);\n\n slot.state = SlotState.Filled;\n emit SlotFilled(requestId, slotIndex);\n\n if (\n context.slotsFilled == request.ask.slots &&\n context.state == RequestState.New // Only New requests can \"start\" the requests\n ) {\n context.state = RequestState.Started;\n context.startedAt = uint64(block.timestamp);\n emit RequestFulfilled(requestId);\n }\n }\n\n /**\n * @notice Frees a slot, paying out rewards and returning collateral for\n finished or cancelled requests to the host that has filled the slot.\n * @param slotId id of the slot to free\n * @dev The host that filled the slot must have initiated the transaction\n (msg.sender). This overload allows `rewardRecipient` and\n `collateralRecipient` to be optional.\n */\n function freeSlot(SlotId slotId) public slotIsNotFree(slotId) {\n return freeSlot(slotId, msg.sender, msg.sender);\n }\n\n /**\n * @notice Frees a slot, paying out rewards and returning collateral for\n finished or cancelled requests.\n * @param slotId id of the slot to free\n * @param rewardRecipient address to send rewards to\n * @param collateralRecipient address to refund collateral to\n */\n function freeSlot(\n SlotId slotId,\n address rewardRecipient,\n address collateralRecipient\n ) public slotIsNotFree(slotId) {\n Slot storage slot = _slots[slotId];\n if (slot.host != msg.sender) revert Marketplace_InvalidSlotHost();\n\n SlotState state = slotState(slotId);\n if (state == SlotState.Paid) revert Marketplace_AlreadyPaid();\n\n if (state == SlotState.Finished) {\n _payoutSlot(slot.requestId, slotId, rewardRecipient, collateralRecipient);\n } else if (state == SlotState.Cancelled) {\n _payoutCancelledSlot(\n slot.requestId,\n slotId,\n rewardRecipient,\n collateralRecipient\n );\n } else if (state == SlotState.Failed) {\n _removeFromMySlots(msg.sender, slotId);\n } else if (state == SlotState.Filled) {\n // free slot without returning collateral, effectively a 100% slash\n _forciblyFreeSlot(slotId);\n }\n }\n\n function _challengeToFieldElement(\n bytes32 challenge\n ) internal pure returns (uint256) {\n // use only 31 bytes of the challenge to ensure that it fits into the field\n bytes32 truncated = bytes32(bytes31(challenge));\n // convert from little endian to big endian\n bytes32 bigEndian = _byteSwap(truncated);\n // convert bytes to integer\n return uint256(bigEndian);\n }\n\n function _merkleRootToFieldElement(\n bytes32 merkleRoot\n ) internal pure returns (uint256) {\n // convert from little endian to big endian\n bytes32 bigEndian = _byteSwap(merkleRoot);\n // convert bytes to integer\n return uint256(bigEndian);\n }\n\n function submitProof(\n SlotId id,\n Groth16Proof calldata proof\n ) public requestIsKnown(_slots[id].requestId) {\n Slot storage slot = _slots[id];\n\n if (msg.sender != slot.host) {\n revert Marketplace_ProofNotSubmittedByHost();\n }\n\n Request storage request = _requests[slot.requestId];\n uint256[] memory pubSignals = new uint256[](3);\n pubSignals[0] = _challengeToFieldElement(getChallenge(id));\n pubSignals[1] = _merkleRootToFieldElement(request.content.merkleRoot);\n pubSignals[2] = slot.slotIndex;\n _proofReceived(id, proof, pubSignals);\n }\n\n function canMarkProofAsMissing(\n SlotId slotId,\n Period period\n ) public view slotAcceptsProofs(slotId) {\n _canMarkProofAsMissing(slotId, period);\n }\n\n function markProofAsMissing(\n SlotId slotId,\n Period period\n ) public slotAcceptsProofs(slotId) {\n _markProofAsMissing(slotId, period);\n\n Slot storage slot = _slots[slotId];\n Request storage request = _requests[slot.requestId];\n\n uint256 slashedAmount = (request.ask.collateralPerSlot() *\n _config.collateral.slashPercentage) / 100;\n\n uint256 validatorRewardAmount = (slashedAmount *\n _config.collateral.validatorRewardPercentage) / 100;\n _marketplaceTotals.sent += validatorRewardAmount;\n\n if (!_token.transfer(msg.sender, validatorRewardAmount)) {\n revert Marketplace_TransferFailed();\n }\n\n slot.currentCollateral -= slashedAmount;\n if (missingProofs(slotId) >= _config.collateral.maxNumberOfSlashes) {\n // When the number of slashings is at or above the allowed amount,\n // free the slot.\n _forciblyFreeSlot(slotId);\n }\n }\n\n /**\n * @notice Abandons the slot without returning collateral, effectively slashing the\n entire collateral.\n * @param slotId SlotId of the slot to free.\n * @dev _slots[slotId] is deleted, resetting _slots[slotId].currentCollateral\n to 0.\n */\n function _forciblyFreeSlot(SlotId slotId) internal {\n Slot storage slot = _slots[slotId];\n RequestId requestId = slot.requestId;\n RequestContext storage context = _requestContexts[requestId];\n\n // We need to refund the amount of payout of the current node to the `fundsToReturnToClient` so\n // we keep correctly the track of the funds that needs to be returned at the end.\n context.fundsToReturnToClient += _slotPayout(requestId, slot.filledAt);\n\n _removeFromMySlots(slot.host, slotId);\n _reservations[slotId].clear(); // We purge all the reservations for the slot\n slot.state = SlotState.Repair;\n slot.filledAt = 0;\n slot.currentCollateral = 0;\n slot.host = address(0);\n context.slotsFilled -= 1;\n emit SlotFreed(requestId, slot.slotIndex);\n _resetMissingProofs(slotId);\n\n Request storage request = _requests[requestId];\n uint256 slotsLost = request.ask.slots - context.slotsFilled;\n if (\n slotsLost > request.ask.maxSlotLoss &&\n context.state == RequestState.Started\n ) {\n context.state = RequestState.Failed;\n context.endsAt = uint64(block.timestamp) - 1;\n emit RequestFailed(requestId);\n }\n }\n\n function _payoutSlot(\n RequestId requestId,\n SlotId slotId,\n address rewardRecipient,\n address collateralRecipient\n ) private requestIsKnown(requestId) {\n RequestContext storage context = _requestContexts[requestId];\n Request storage request = _requests[requestId];\n context.state = RequestState.Finished;\n Slot storage slot = _slots[slotId];\n\n _removeFromMyRequests(request.client, requestId);\n _removeFromMySlots(slot.host, slotId);\n\n uint256 payoutAmount = _slotPayout(requestId, slot.filledAt);\n uint256 collateralAmount = slot.currentCollateral;\n _marketplaceTotals.sent += (payoutAmount + collateralAmount);\n slot.state = SlotState.Paid;\n if (!_token.transfer(rewardRecipient, payoutAmount)) {\n revert Marketplace_TransferFailed();\n }\n\n if (!_token.transfer(collateralRecipient, collateralAmount)) {\n revert Marketplace_TransferFailed();\n }\n }\n\n /**\n * @notice Pays out a host for duration of time that the slot was filled, and\n returns the collateral.\n * @dev The payouts are sent to the rewardRecipient, and collateral is returned\n to the host address.\n * @param requestId RequestId of the request that contains the slot to be paid\n out.\n * @param slotId SlotId of the slot to be paid out.\n */\n function _payoutCancelledSlot(\n RequestId requestId,\n SlotId slotId,\n address rewardRecipient,\n address collateralRecipient\n ) private requestIsKnown(requestId) {\n Slot storage slot = _slots[slotId];\n _removeFromMySlots(slot.host, slotId);\n\n uint256 payoutAmount = _slotPayout(\n requestId,\n slot.filledAt,\n requestExpiry(requestId)\n );\n uint256 collateralAmount = slot.currentCollateral;\n _marketplaceTotals.sent += (payoutAmount + collateralAmount);\n slot.state = SlotState.Paid;\n if (!_token.transfer(rewardRecipient, payoutAmount)) {\n revert Marketplace_TransferFailed();\n }\n\n if (!_token.transfer(collateralRecipient, collateralAmount)) {\n revert Marketplace_TransferFailed();\n }\n }\n\n /**\n * @notice Withdraws remaining storage request funds back to the client that\n deposited them.\n * @dev Request must be cancelled, failed or finished, and the\n transaction must originate from the depositor address.\n * @param requestId the id of the request\n */\n function withdrawFunds(RequestId requestId) public {\n withdrawFunds(requestId, msg.sender);\n }\n\n /**\n * @notice Withdraws storage request funds to the provided address.\n * @dev Request must be expired, must be in RequestState.New, and the\n transaction must originate from the depositer address.\n * @param requestId the id of the request\n * @param withdrawRecipient address to return the remaining funds to\n */\n function withdrawFunds(\n RequestId requestId,\n address withdrawRecipient\n ) public requestIsKnown(requestId) {\n Request storage request = _requests[requestId];\n RequestContext storage context = _requestContexts[requestId];\n\n if (request.client != msg.sender) revert Marketplace_InvalidClientAddress();\n\n RequestState state = requestState(requestId);\n if (\n state != RequestState.Cancelled &&\n state != RequestState.Failed &&\n state != RequestState.Finished\n ) {\n revert Marketplace_InvalidState();\n }\n\n // fundsToReturnToClient == 0 is used for \"double-spend\" protection, once the funds are withdrawn\n // then this variable is set to 0.\n if (context.fundsToReturnToClient == 0)\n revert Marketplace_NothingToWithdraw();\n\n if (state == RequestState.Cancelled) {\n context.state = RequestState.Cancelled;\n emit RequestCancelled(requestId);\n\n // `fundsToReturnToClient` currently tracks funds to be returned for requests that successfully finish.\n // When requests are cancelled, funds earmarked for payment for the duration\n // between request expiry and request end (for every slot that was filled), should be returned to the client.\n // Update `fundsToReturnToClient` to reflect this.\n context.fundsToReturnToClient +=\n context.slotsFilled *\n _slotPayout(requestId, requestExpiry(requestId));\n } else if (state == RequestState.Failed) {\n // For Failed requests the client is refunded whole amount.\n context.fundsToReturnToClient = request.maxPrice();\n } else {\n context.state = RequestState.Finished;\n }\n\n _removeFromMyRequests(request.client, requestId);\n\n uint256 amount = context.fundsToReturnToClient;\n _marketplaceTotals.sent += amount;\n\n if (!_token.transfer(withdrawRecipient, amount)) {\n revert Marketplace_TransferFailed();\n }\n\n // We zero out the funds tracking in order to prevent double-spends\n context.fundsToReturnToClient = 0;\n }\n\n function getActiveSlot(\n SlotId slotId\n ) public view returns (ActiveSlot memory) {\n // Modifier `slotIsNotFree(slotId)` works here, but using the modifier\n // causes hardhat to return an error \"reverted with an unrecognized custom\n // error (return data: 0x8b41ec7f)\".\n if (_slots[slotId].state == SlotState.Free) revert Marketplace_SlotIsFree();\n Slot storage slot = _slots[slotId];\n ActiveSlot memory activeSlot;\n activeSlot.request = _requests[slot.requestId];\n activeSlot.slotIndex = slot.slotIndex;\n return activeSlot;\n }\n\n modifier requestIsKnown(RequestId requestId) {\n if (_requests[requestId].client == address(0))\n revert Marketplace_UnknownRequest();\n\n _;\n }\n\n function getRequest(\n RequestId requestId\n ) public view requestIsKnown(requestId) returns (Request memory) {\n return _requests[requestId];\n }\n\n modifier slotIsNotFree(SlotId slotId) {\n if (_slots[slotId].state == SlotState.Free) revert Marketplace_SlotIsFree();\n _;\n }\n\n modifier slotAcceptsProofs(SlotId slotId) {\n if (slotState(slotId) != SlotState.Filled)\n revert Marketplace_SlotNotAcceptingProofs();\n _;\n }\n\n function requestEnd(RequestId requestId) public view returns (uint64) {\n RequestState state = requestState(requestId);\n if (state == RequestState.New || state == RequestState.Started) {\n return _requestContexts[requestId].endsAt;\n }\n if (state == RequestState.Cancelled) {\n return _requestContexts[requestId].expiresAt;\n }\n return\n uint64(Math.min(_requestContexts[requestId].endsAt, block.timestamp));\n }\n\n function requestExpiry(RequestId requestId) public view returns (uint64) {\n return _requestContexts[requestId].expiresAt;\n }\n\n /**\n * @notice Calculates the amount that should be paid out to a host that successfully finished the request\n * @param requestId RequestId of the request used to calculate the payout\n * amount.\n * @param startingTimestamp timestamp indicating when a host filled a slot and\n * started providing proofs.\n */\n function _slotPayout(\n RequestId requestId,\n uint64 startingTimestamp\n ) private view returns (uint256) {\n return\n _slotPayout(\n requestId,\n startingTimestamp,\n _requestContexts[requestId].endsAt\n );\n }\n\n /// @notice Calculates the amount that should be paid out to a host based on the specified time frame.\n function _slotPayout(\n RequestId requestId,\n uint64 startingTimestamp,\n uint64 endingTimestamp\n ) private view returns (uint256) {\n Request storage request = _requests[requestId];\n if (startingTimestamp >= endingTimestamp)\n revert Marketplace_StartNotBeforeExpiry();\n return\n (endingTimestamp - startingTimestamp) *\n request.ask.pricePerSlotPerSecond();\n }\n\n function getHost(SlotId slotId) public view returns (address) {\n return _slots[slotId].host;\n }\n\n function requestState(\n RequestId requestId\n ) public view requestIsKnown(requestId) returns (RequestState) {\n RequestContext storage context = _requestContexts[requestId];\n if (\n context.state == RequestState.New &&\n uint64(block.timestamp) > requestExpiry(requestId)\n ) {\n return RequestState.Cancelled;\n } else if (\n (context.state == RequestState.Started ||\n context.state == RequestState.New) &&\n uint64(block.timestamp) > context.endsAt\n ) {\n return RequestState.Finished;\n } else {\n return context.state;\n }\n }\n\n function slotState(\n SlotId slotId\n ) public view override(Proofs, SlotReservations) returns (SlotState) {\n Slot storage slot = _slots[slotId];\n if (RequestId.unwrap(slot.requestId) == 0) {\n return SlotState.Free;\n }\n RequestState reqState = requestState(slot.requestId);\n if (slot.state == SlotState.Paid) {\n return SlotState.Paid;\n }\n if (reqState == RequestState.Cancelled) {\n return SlotState.Cancelled;\n }\n if (reqState == RequestState.Finished) {\n return SlotState.Finished;\n }\n if (reqState == RequestState.Failed) {\n return SlotState.Failed;\n }\n return slot.state;\n }\n\n function slotProbability(\n SlotId slotId\n ) public view override returns (uint256) {\n Slot storage slot = _slots[slotId];\n Request storage request = _requests[slot.requestId];\n return\n (request.ask.proofProbability * (256 - _config.proofs.downtime)) / 256;\n }\n\n function _transferFrom(address sender, uint256 amount) internal {\n address receiver = address(this);\n if (!_token.transferFrom(sender, receiver, amount))\n revert Marketplace_TransferFailed();\n }\n\n event StorageRequested(RequestId requestId, Ask ask, uint64 expiry);\n event RequestFulfilled(RequestId indexed requestId);\n event RequestFailed(RequestId indexed requestId);\n event SlotFilled(RequestId indexed requestId, uint64 slotIndex);\n event SlotFreed(RequestId indexed requestId, uint64 slotIndex);\n event RequestCancelled(RequestId indexed requestId);\n\n struct MarketplaceTotals {\n uint256 received;\n uint256 sent;\n }\n}\n" }, "contracts/Periods.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ncontract Periods {\n error Periods_InvalidSecondsPerPeriod();\n\n type Period is uint64;\n\n uint64 internal immutable _secondsPerPeriod;\n\n constructor(uint64 secondsPerPeriod) {\n if (secondsPerPeriod == 0) {\n revert Periods_InvalidSecondsPerPeriod();\n }\n _secondsPerPeriod = secondsPerPeriod;\n }\n\n function _periodOf(uint64 timestamp) internal view returns (Period) {\n return Period.wrap(timestamp / _secondsPerPeriod);\n }\n\n function _blockPeriod() internal view returns (Period) {\n return _periodOf(uint64(block.timestamp));\n }\n\n function _nextPeriod(Period period) internal pure returns (Period) {\n return Period.wrap(Period.unwrap(period) + 1);\n }\n\n function _periodStart(Period period) internal view returns (uint64) {\n return Period.unwrap(period) * _secondsPerPeriod;\n }\n\n function _periodEnd(Period period) internal view returns (uint64) {\n return _periodStart(_nextPeriod(period));\n }\n\n function _isBefore(Period a, Period b) internal pure returns (bool) {\n return Period.unwrap(a) < Period.unwrap(b);\n }\n\n function _isAfter(Period a, Period b) internal pure returns (bool) {\n return _isBefore(b, a);\n }\n}\n" }, "contracts/Proofs.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"./Configuration.sol\";\nimport \"./Requests.sol\";\nimport \"./Periods.sol\";\nimport \"./Groth16.sol\";\n\n/**\n * @title Proofs\n * @notice Abstract contract that handles proofs tracking, validation and reporting functionality\n */\nabstract contract Proofs is Periods {\n error Proofs_InsufficientBlockHeight();\n error Proofs_InvalidProof();\n error Proofs_ProofAlreadySubmitted();\n error Proofs_PeriodNotEnded();\n error Proofs_ValidationTimedOut();\n error Proofs_ProofNotMissing();\n error Proofs_ProofNotRequired();\n error Proofs_ProofAlreadyMarkedMissing();\n\n ProofConfig private _config;\n IGroth16Verifier private _verifier;\n\n /**\n * Creation of the contract requires at least 256 mined blocks!\n * @param config Proving configuration\n */\n constructor(\n ProofConfig memory config,\n IGroth16Verifier verifier\n ) Periods(config.period) {\n if (block.number <= 256) {\n revert Proofs_InsufficientBlockHeight();\n }\n\n _config = config;\n _verifier = verifier;\n }\n\n mapping(SlotId => uint64) private _slotStarts;\n mapping(SlotId => uint64) private _missed;\n mapping(SlotId => mapping(Period => bool)) private _received;\n mapping(SlotId => mapping(Period => bool)) private _missing;\n\n function slotState(SlotId id) public view virtual returns (SlotState);\n\n /**\n * @param id Slot's ID\n * @return Integer which specifies the probability of how often the proofs will be required. Lower number means higher probability.\n */\n function slotProbability(SlotId id) public view virtual returns (uint256);\n\n /**\n * @return Number of missed proofs since Slot was Filled\n */\n function missingProofs(SlotId slotId) public view returns (uint64) {\n return _missed[slotId];\n }\n\n /**\n * @param slotId Slot's ID for which the proofs should be reset\n * @notice Resets the missing proofs counter to zero\n */\n function _resetMissingProofs(SlotId slotId) internal {\n _missed[slotId] = 0;\n }\n\n /**\n * @param id Slot's ID for which the proofs should be started to require\n * @notice Notes down the block's timestamp as Slot's starting time for requiring proofs\n * and saves the required probability.\n */\n function _startRequiringProofs(SlotId id) internal {\n _slotStarts[id] = uint64(block.timestamp);\n }\n\n /**\n * @param id Slot's ID for which the pointer should be calculated\n * @param period Period for which the pointer should be calculated\n * @return Uint8 pointer that is stable over current Period, ie an integer offset [0-255] of the last 256 blocks, pointing to a block that remains constant for the entire Period's duration.\n * @dev For more information see [timing of storage proofs](https://github.com/codex-storage/codex-research/blob/41c4b4409d2092d0a5475aca0f28995034e58d14/design/storage-proof-timing.md)\n */\n function _getPointer(SlotId id, Period period) internal view returns (uint8) {\n uint256 blockNumber = block.number % 256;\n uint256 periodNumber = (Period.unwrap(period) * _config.downtimeProduct) %\n 256;\n uint256 idOffset = uint256(SlotId.unwrap(id)) % 256;\n uint256 pointer = (blockNumber + periodNumber + idOffset) % 256;\n return uint8(pointer);\n }\n\n /**\n * @param id Slot's ID for which the pointer should be calculated\n * @return Uint8 pointer that is stable over current Period, ie an integer offset [0-255] of the last 256 blocks, pointing to a block that remains constant for the entire Period's duration.\n * @dev For more information see [timing of storage proofs](https://github.com/codex-storage/codex-research/blob/41c4b4409d2092d0a5475aca0f28995034e58d14/design/storage-proof-timing.md)\n */\n function getPointer(SlotId id) public view returns (uint8) {\n return _getPointer(id, _blockPeriod());\n }\n\n /**\n * @param pointer Integer [0-255] that indicates an offset of the last 256 blocks, pointing to a block that remains constant for the entire Period's duration.\n * @return Challenge that should be used for generation of proofs\n */\n function _getChallenge(uint8 pointer) internal view returns (bytes32) {\n bytes32 hash = blockhash(block.number - 1 - pointer);\n assert(uint256(hash) != 0);\n return keccak256(abi.encode(hash));\n }\n\n /**\n * @param id Slot's ID for which the challenge should be calculated\n * @param period Period for which the challenge should be calculated\n * @return Challenge that should be used for generation of proofs\n */\n function _getChallenge(\n SlotId id,\n Period period\n ) internal view returns (bytes32) {\n return _getChallenge(_getPointer(id, period));\n }\n\n /**\n * @param id Slot's ID for which the challenge should be calculated\n * @return Challenge for current Period that should be used for generation of proofs\n */\n function getChallenge(SlotId id) public view returns (bytes32) {\n return _getChallenge(id, _blockPeriod());\n }\n\n /**\n * @param id Slot's ID for which the requirements are gathered. If the Slot's state is other than Filled, `false` is always returned.\n * @param period Period for which the requirements are gathered.\n */\n function _getProofRequirement(\n SlotId id,\n Period period\n ) internal view returns (bool isRequired, uint8 pointer) {\n SlotState state = slotState(id);\n Period start = _periodOf(_slotStarts[id]);\n if (state != SlotState.Filled || !_isAfter(period, start)) {\n return (false, 0);\n }\n pointer = _getPointer(id, period);\n bytes32 challenge = _getChallenge(pointer);\n\n /// Scaling of the probability according the downtime configuration\n /// See: https://github.com/codex-storage/codex-research/blob/41c4b4409d2092d0a5475aca0f28995034e58d14/design/storage-proof-timing.md#pointer-downtime\n uint256 probability = slotProbability(id);\n isRequired = probability == 0 || uint256(challenge) % probability == 0;\n }\n\n /**\n * See isProofRequired\n */\n function _isProofRequired(\n SlotId id,\n Period period\n ) internal view returns (bool) {\n bool isRequired;\n uint8 pointer;\n (isRequired, pointer) = _getProofRequirement(id, period);\n return isRequired && pointer >= _config.downtime;\n }\n\n /**\n * @param id Slot's ID for which the proof requirements should be checked. If the Slot's state is other than Filled, `false` is always returned.\n * @return bool indicating if proof is required for current period\n */\n function isProofRequired(SlotId id) public view returns (bool) {\n return _isProofRequired(id, _blockPeriod());\n }\n\n /**\n * Proof Downtime specifies part of the Period when the proof is not required even\n * if the proof should be required. This function returns true if the pointer is\n * in downtime (hence no proof required now) and at the same time the proof\n * will be required later on in the Period.\n *\n * @dev for more info about downtime see [timing of storage proofs](https://github.com/codex-storage/codex-research/blob/41c4b4409d2092d0a5475aca0f28995034e58d14/design/storage-proof-timing.md#pointer-downtime)\n * @param id SlotId for which the proof requirements should be checked. If the Slot's state is other than Filled, `false` is always returned.\n * @return bool\n */\n function willProofBeRequired(SlotId id) public view returns (bool) {\n bool isRequired;\n uint8 pointer;\n (isRequired, pointer) = _getProofRequirement(id, _blockPeriod());\n return isRequired && pointer < _config.downtime;\n }\n\n /**\n * Function used for submitting and verification of the proofs.\n *\n * @dev Reverts when proof is invalid or had been already submitted.\n * @dev Emits ProofSubmitted event.\n * @param id Slot's ID for which the proof requirements should be checked\n * @param proof Groth16 proof\n * @param pubSignals Proofs public input\n */\n function _proofReceived(\n SlotId id,\n Groth16Proof calldata proof,\n uint[] memory pubSignals\n ) internal {\n if (_received[id][_blockPeriod()]) revert Proofs_ProofAlreadySubmitted();\n if (!_verifier.verify(proof, pubSignals)) revert Proofs_InvalidProof();\n\n _received[id][_blockPeriod()] = true;\n emit ProofSubmitted(id);\n }\n\n /**\n * Function used to mark proof as missing.\n *\n * @param id Slot's ID for which the proof is missing\n * @param missedPeriod Period for which the proof was missed\n * @dev Reverts when:\n * - missedPeriod has not ended yet ended\n * - missing proof was time-barred\n * - proof was submitted\n * - proof was not required for missedPeriod period\n * - proof was already marked as missing\n */\n function _markProofAsMissing(SlotId id, Period missedPeriod) internal {\n _canMarkProofAsMissing(id, missedPeriod);\n\n _missing[id][missedPeriod] = true;\n _missed[id] += 1;\n }\n\n function _canMarkProofAsMissing(\n SlotId id,\n Period missedPeriod\n ) internal view {\n uint256 end = _periodEnd(missedPeriod);\n if (end >= block.timestamp) revert Proofs_PeriodNotEnded();\n if (block.timestamp >= end + _config.timeout)\n revert Proofs_ValidationTimedOut();\n if (_received[id][missedPeriod]) revert Proofs_ProofNotMissing();\n if (!_isProofRequired(id, missedPeriod)) revert Proofs_ProofNotRequired();\n if (_missing[id][missedPeriod]) revert Proofs_ProofAlreadyMarkedMissing();\n }\n\n event ProofSubmitted(SlotId id);\n}\n" }, "contracts/Requests.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ntype RequestId is bytes32;\ntype SlotId is bytes32;\n\nstruct Request {\n address client;\n Ask ask;\n Content content;\n uint64 expiry; // amount of seconds since start of the request at which this request expires\n bytes32 nonce; // random nonce to differentiate between similar requests\n}\n\nstruct Ask {\n uint256 proofProbability; // how often storage proofs are required\n uint256 pricePerBytePerSecond; // amount of tokens paid per second per byte to hosts\n uint256 collateralPerByte; // amount of tokens per byte required to be deposited by the hosts in order to fill the slot\n uint64 slots; // the number of requested slots\n uint64 slotSize; // amount of storage per slot (in number of bytes)\n uint64 duration; // how long content should be stored (in seconds)\n uint64 maxSlotLoss; // Max slots that can be lost without data considered to be lost\n}\n\nstruct Content {\n bytes cid; // content id, used to download the dataset\n bytes32 merkleRoot; // merkle root of the dataset, used to verify storage proofs\n}\n\nenum RequestState {\n New, // [default] waiting to fill slots\n Started, // all slots filled, accepting regular proofs\n Cancelled, // not enough slots filled before expiry\n Finished, // successfully completed\n Failed // too many nodes have failed to provide proofs, data lost\n}\n\nenum SlotState {\n Free, // [default] not filled yet\n Filled, // host has filled slot\n Finished, // successfully completed\n Failed, // the request has failed\n Paid, // host has been paid\n Cancelled, // when request was cancelled then slot is cancelled as well\n Repair // when slot slot was forcible freed (host was kicked out from hosting the slot because of too many missed proofs) and needs to be repaired\n}\n\nlibrary AskHelpers {\n function collateralPerSlot(Ask memory ask) internal pure returns (uint256) {\n return ask.collateralPerByte * ask.slotSize;\n }\n\n function pricePerSlotPerSecond(\n Ask memory ask\n ) internal pure returns (uint256) {\n return ask.pricePerBytePerSecond * ask.slotSize;\n }\n}\n\nlibrary Requests {\n using AskHelpers for Ask;\n\n function id(Request memory request) internal pure returns (RequestId) {\n return RequestId.wrap(keccak256(abi.encode(request)));\n }\n\n function slotId(\n RequestId requestId,\n uint64 slotIndex\n ) internal pure returns (SlotId) {\n return SlotId.wrap(keccak256(abi.encode(requestId, slotIndex)));\n }\n\n function toRequestIds(\n bytes32[] memory ids\n ) internal pure returns (RequestId[] memory result) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n result := ids\n }\n }\n\n function toSlotIds(\n bytes32[] memory ids\n ) internal pure returns (SlotId[] memory result) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n result := ids\n }\n }\n\n function maxPrice(Request memory request) internal pure returns (uint256) {\n return\n request.ask.slots *\n request.ask.duration *\n request.ask.pricePerSlotPerSecond();\n }\n}\n" }, "contracts/SlotReservations.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"./Requests.sol\";\nimport \"./Configuration.sol\";\n\nabstract contract SlotReservations {\n using EnumerableSet for EnumerableSet.AddressSet;\n error SlotReservations_ReservationNotAllowed();\n\n mapping(SlotId => EnumerableSet.AddressSet) internal _reservations;\n SlotReservationsConfig private _config;\n\n constructor(SlotReservationsConfig memory config) {\n _config = config;\n }\n\n function slotState(SlotId id) public view virtual returns (SlotState);\n\n function reserveSlot(RequestId requestId, uint64 slotIndex) public {\n if (!canReserveSlot(requestId, slotIndex))\n revert SlotReservations_ReservationNotAllowed();\n\n SlotId slotId = Requests.slotId(requestId, slotIndex);\n _reservations[slotId].add(msg.sender);\n\n if (_reservations[slotId].length() == _config.maxReservations) {\n emit SlotReservationsFull(requestId, slotIndex);\n }\n }\n\n function canReserveSlot(\n RequestId requestId,\n uint64 slotIndex\n ) public view returns (bool) {\n address host = msg.sender;\n SlotId slotId = Requests.slotId(requestId, slotIndex);\n SlotState state = slotState(slotId);\n return\n // TODO: add in check for address inside of expanding window\n (state == SlotState.Free || state == SlotState.Repair) &&\n (_reservations[slotId].length() < _config.maxReservations) &&\n (!_reservations[slotId].contains(host));\n }\n\n event SlotReservationsFull(RequestId indexed requestId, uint64 slotIndex);\n}\n" }, "contracts/StateRetrieval.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"./Requests.sol\";\n\ncontract StateRetrieval {\n using EnumerableSet for EnumerableSet.Bytes32Set;\n using Requests for bytes32[];\n\n mapping(address => EnumerableSet.Bytes32Set) private _requestsPerClient;\n mapping(address => EnumerableSet.Bytes32Set) private _slotsPerHost;\n\n function myRequests() public view returns (RequestId[] memory) {\n return _requestsPerClient[msg.sender].values().toRequestIds();\n }\n\n function mySlots() public view returns (SlotId[] memory) {\n return _slotsPerHost[msg.sender].values().toSlotIds();\n }\n\n function _hasSlots(address host) internal view returns (bool) {\n return _slotsPerHost[host].length() > 0;\n }\n\n function _addToMyRequests(address client, RequestId requestId) internal {\n _requestsPerClient[client].add(RequestId.unwrap(requestId));\n }\n\n function _addToMySlots(address host, SlotId slotId) internal {\n _slotsPerHost[host].add(SlotId.unwrap(slotId));\n }\n\n function _removeFromMyRequests(address client, RequestId requestId) internal {\n _requestsPerClient[client].remove(RequestId.unwrap(requestId));\n }\n\n function _removeFromMySlots(address host, SlotId slotId) internal {\n _slotsPerHost[host].remove(SlotId.unwrap(slotId));\n }\n}\n" }, "contracts/TestEndian.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./Endian.sol\";\n\ncontract TestEndian is Endian {\n function byteSwap(bytes32 input) public pure returns (bytes32) {\n return _byteSwap(input);\n }\n}\n" }, "contracts/TestMarketplace.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./Marketplace.sol\";\n\n// exposes internal functions of Marketplace for testing\ncontract TestMarketplace is Marketplace {\n constructor(\n MarketplaceConfig memory config,\n IERC20 token,\n IGroth16Verifier verifier\n )\n Marketplace(config, token, verifier) // solhint-disable-next-line no-empty-blocks\n {}\n\n function forciblyFreeSlot(SlotId slotId) public {\n _forciblyFreeSlot(slotId);\n }\n\n function getSlotCollateral(SlotId slotId) public view returns (uint256) {\n return _slots[slotId].currentCollateral;\n }\n\n function challengeToFieldElement(\n bytes32 challenge\n ) public pure returns (uint256) {\n return _challengeToFieldElement(challenge);\n }\n\n function merkleRootToFieldElement(\n bytes32 merkleRoot\n ) public pure returns (uint256) {\n return _merkleRootToFieldElement(merkleRoot);\n }\n}\n" }, "contracts/TestProofs.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./Proofs.sol\";\n\n// exposes internal functions of Proofs for testing\ncontract TestProofs is Proofs {\n mapping(SlotId => SlotState) private _states;\n mapping(SlotId => uint256) private _probabilities;\n // A _config object exist in Proofs but it is private.\n // Better to duplicate this config in the test implementation\n // rather than modifiying the existing implementation and change\n // private to internal, which may cause problems in the Marketplace contract.\n ProofConfig private _proofConfig;\n\n constructor(\n ProofConfig memory config,\n IGroth16Verifier verifier\n ) Proofs(config, verifier) {\n _proofConfig = config;\n }\n\n function slotState(SlotId slotId) public view override returns (SlotState) {\n return _states[slotId];\n }\n\n function startRequiringProofs(SlotId slot) public {\n _startRequiringProofs(slot);\n }\n\n function markProofAsMissing(SlotId id, Period period) public {\n _markProofAsMissing(id, period);\n }\n\n function proofReceived(\n SlotId id,\n Groth16Proof calldata proof,\n uint[] memory pubSignals\n ) public {\n _proofReceived(id, proof, pubSignals);\n }\n\n function setSlotState(SlotId id, SlotState state) public {\n _states[id] = state;\n }\n\n function slotProbability(\n SlotId id\n ) public view virtual override returns (uint256) {\n return (_probabilities[id] * (256 - _proofConfig.downtime)) / 256;\n }\n\n function setSlotProbability(SlotId id, uint256 probability) public {\n _probabilities[id] = probability;\n }\n}\n" }, "contracts/TestSlotReservations.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./SlotReservations.sol\";\n\ncontract TestSlotReservations is SlotReservations {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(SlotId => SlotState) private _states;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(SlotReservationsConfig memory config) SlotReservations(config) {}\n\n function contains(SlotId slotId, address host) public view returns (bool) {\n return _reservations[slotId].contains(host);\n }\n\n function length(SlotId slotId) public view returns (uint256) {\n return _reservations[slotId].length();\n }\n\n function slotState(SlotId slotId) public view override returns (SlotState) {\n return _states[slotId];\n }\n\n function setSlotState(SlotId id, SlotState state) public {\n _states[id] = state;\n }\n}\n" }, "contracts/TestToken.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract TestToken is ERC20 {\n // solhint-disable-next-line no-empty-blocks\n constructor() ERC20(\"TestToken\", \"TST\") {}\n\n function mint(address holder, uint256 amount) public {\n _mint(holder, amount);\n }\n}\n" }, "contracts/TestVerifier.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"./Groth16.sol\";\n\ncontract TestVerifier is IGroth16Verifier {\n function verify(\n Groth16Proof calldata proof,\n uint[] calldata\n ) external pure returns (bool) {\n // accepts any proof, except the proof with all zero values\n return\n !(proof.a.x == 0 &&\n proof.a.y == 0 &&\n proof.b.x.real == 0 &&\n proof.b.x.imag == 0 &&\n proof.b.y.real == 0 &&\n proof.b.y.imag == 0 &&\n proof.c.x == 0 &&\n proof.c.y == 0);\n }\n}\n" }, "contracts/Vault.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Pausable.sol\";\nimport \"./vault/VaultBase.sol\";\n\n/// A vault provides a means for smart contracts to control allocation of ERC20\n/// tokens without the need to hold the ERC20 tokens themselves, thereby\n/// decreasing their own attack surface.\n///\n/// A vault keeps track of funds for a smart contract. This smart contract is\n/// called the controller of the funds. Each controller has its own independent\n/// set of funds. Each fund has a number of accounts.\n///\n/// Vault -> Controller -> Fund -> Account\n///\n/// Funds are identified by a unique 32 byte identifier, chosen by the\n/// controller.\n///\n/// An account has a balance, of which a part can be designated. Designated\n/// tokens can no longer be transfered to another account, although they can be\n/// burned.\n/// Accounts are identified by the address of the account holder, and an id that\n/// can be used to create different accounts for the same holder.\n///\n/// A typical flow in which a controller uses the vault to handle funds:\n/// 1. the controller chooses a unique id for the fund\n/// 2. the controller locks the fund for an amount of time\n/// 3. the controller deposits ERC20 tokens into the fund\n/// 4. the controller transfers tokens between accounts in the fund\n/// 5. the fund unlocks after a while, freezing the account balances\n/// 6. the controller withdraws ERC20 tokens from the fund for an account holder,\n/// or the account holder initiates the withdrawal itself\n///\n/// The vault makes it harder for an attacker to extract funds, through several\n/// mechanisms:\n/// - tokens in a fund can only be reassigned while the fund is time-locked, and\n/// only be withdrawn after the lock unlocks, delaying an attacker's attempt\n/// at extraction of tokens from the vault\n/// - tokens in a fund can not be reassigned when the lock unlocks, ensuring\n/// that they can no longer be reassigned to an attacker\n/// - when storing collateral, it can be designated for the collateral provider,\n/// ensuring that it cannot be reassigned to an attacker\n/// - malicious upgrades to a fund controller cannot prevent account holders\n/// from withdrawing their tokens\n/// - burning tokens in a fund ensures that these tokens can no longer be\n/// extracted by an attacker\n///\ncontract Vault is VaultBase, Pausable, Ownable {\n constructor(IERC20 token) VaultBase(token) Ownable(msg.sender) {}\n\n /// Creates an account id that encodes the address of the account holder, and\n /// a discriminator. The discriminator can be used to create different\n /// accounts within a fund that all belong to the same account holder.\n function encodeAccountId(\n address holder,\n bytes12 discriminator\n ) public pure returns (AccountId) {\n return Accounts.encodeId(holder, discriminator);\n }\n\n /// Extracts the address of the account holder and the discriminator from the\n /// account id.\n function decodeAccountId(\n AccountId id\n ) public pure returns (address holder, bytes12 discriminator) {\n return Accounts.decodeId(id);\n }\n\n /// The amount of tokens that are currently in an account.\n /// This includes available and designated tokens. Available tokens can be\n /// transfered to other accounts, but designated tokens cannot.\n function getBalance(\n FundId fundId,\n AccountId accountId\n ) public view returns (uint128) {\n Controller controller = Controller.wrap(msg.sender);\n Balance memory balance = _getBalance(controller, fundId, accountId);\n return balance.available + balance.designated;\n }\n\n /// The amount of tokens that are currently designated in an account\n /// These tokens can no longer be transfered to other accounts.\n function getDesignatedBalance(\n FundId fundId,\n AccountId accountId\n ) public view returns (uint128) {\n Controller controller = Controller.wrap(msg.sender);\n Balance memory balance = _getBalance(controller, fundId, accountId);\n return balance.designated;\n }\n\n /// Returns the status of the fund. Most operations on the vault can only be\n /// done by the controller when the funds are locked. Withdrawals can only be\n /// done in the withdrawing state.\n function getFundStatus(FundId fundId) public view returns (FundStatus) {\n Controller controller = Controller.wrap(msg.sender);\n return _getFundStatus(controller, fundId);\n }\n\n /// Returns the expiry time of the lock on the fund. A locked fund unlocks\n /// automatically at this timestamp.\n function getLockExpiry(FundId fundId) public view returns (Timestamp) {\n Controller controller = Controller.wrap(msg.sender);\n return _getLockExpiry(controller, fundId);\n }\n\n /// Locks the fund until the expiry timestamp. The lock expiry can be extended\n /// later, but no more than the maximum timestamp.\n function lock(\n FundId fundId,\n Timestamp expiry,\n Timestamp maximum\n ) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _lock(controller, fundId, expiry, maximum);\n }\n\n /// Delays unlocking of a locked fund. The new expiry should be later than\n /// the existing expiry, but no later than the maximum timestamp that was\n /// provided when locking the fund.\n /// Only allowed when the lock has not unlocked yet.\n function extendLock(FundId fundId, Timestamp expiry) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _extendLock(controller, fundId, expiry);\n }\n\n /// Deposits an amount of tokens into the vault, and adds them to the balance\n /// of the account. ERC20 tokens are transfered from the caller to the vault\n /// contract.\n /// Only allowed when the fund is locked.\n function deposit(\n FundId fundId,\n AccountId accountId,\n uint128 amount\n ) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _deposit(controller, fundId, accountId, amount);\n }\n\n /// Takes an amount of tokens from the account balance and designates them\n /// for the account holder. These tokens are no longer available to be\n /// transfered to other accounts.\n /// Only allowed when the fund is locked.\n function designate(\n FundId fundId,\n AccountId accountId,\n uint128 amount\n ) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _designate(controller, fundId, accountId, amount);\n }\n\n /// Transfers an amount of tokens from one account to the other.\n /// Only allowed when the fund is locked.\n function transfer(\n FundId fundId,\n AccountId from,\n AccountId to,\n uint128 amount\n ) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _transfer(controller, fundId, from, to, amount);\n }\n\n /// Transfers tokens from one account the other over time.\n /// Every second a number of tokens are transfered, until the fund is\n /// unlocked. After flowing into an account, these tokens become designated\n /// tokens, so they cannot be transfered again.\n /// Only allowed when the fund is locked.\n /// Only allowed when the balance is sufficient to sustain the flow until the\n /// fund unlocks, even if the lock expiry time is extended to its maximum.\n function flow(\n FundId fundId,\n AccountId from,\n AccountId to,\n TokensPerSecond rate\n ) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _flow(controller, fundId, from, to, rate);\n }\n\n /// Burns an amount of designated tokens from the account.\n /// Only allowed when the fund is locked.\n function burnDesignated(\n FundId fundId,\n AccountId accountId,\n uint128 amount\n ) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _burnDesignated(controller, fundId, accountId, amount);\n }\n\n /// Burns all tokens from the account.\n /// Only allowed when the fund is locked.\n /// Only allowed when no funds are flowing into or out of the account.\n function burnAccount(\n FundId fundId,\n AccountId accountId\n ) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _burnAccount(controller, fundId, accountId);\n }\n\n /// Freezes a fund. Stops all tokens flows and disallows any operations on the\n /// fund until it unlocks.\n /// Only allowed when the fund is locked.\n function freezeFund(FundId fundId) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _freezeFund(controller, fundId);\n }\n\n /// Transfers all ERC20 tokens in the account out of the vault to the account\n /// owner.\n /// Only allowed when the fund is unlocked.\n /// ⚠️ The account holder can also withdraw itself, so when designing a smart\n /// contract that controls funds in the vault, don't assume that only this\n /// smart contract can initiate a withdrawal ⚠️\n function withdraw(FundId fund, AccountId accountId) public whenNotPaused {\n Controller controller = Controller.wrap(msg.sender);\n _withdraw(controller, fund, accountId);\n }\n\n /// Allows an account holder to withdraw its tokens from a fund directly,\n /// bypassing the need to ask the controller of the fund to initiate the\n /// withdrawal.\n /// Only allowed when the fund is unlocked.\n function withdrawByRecipient(\n Controller controller,\n FundId fund,\n AccountId accountId\n ) public {\n (address holder, ) = Accounts.decodeId(accountId);\n require(msg.sender == holder, VaultOnlyAccountHolder());\n _withdraw(controller, fund, accountId);\n }\n\n function pause() public onlyOwner {\n _pause();\n }\n\n function unpause() public onlyOwner {\n _unpause();\n }\n\n error VaultOnlyAccountHolder();\n}\n" }, "contracts/vault/Accounts.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"./TokenFlows.sol\";\nimport \"./Timestamps.sol\";\n\n/// Used to identify an account. The first 20 bytes consist of the address of\n/// the account holder, and the last 12 bytes consist of a discriminator value.\ntype AccountId is bytes32;\n\n/// Records the token balance and the incoming and outgoing token flows\nstruct Account {\n Balance balance;\n Flow flow;\n}\n\n/// The account balance. Fits in 32 bytes to minimize storage costs.\n/// A uint128 is used to record the amount of tokens, which should be more than\n/// enough. Given a standard 18 decimal places for the ERC20 token, this still\n/// allows for 10^20 whole coins.\nstruct Balance {\n /// Available tokens can be transfered\n uint128 available;\n /// Designated tokens can no longer be transfered\n uint128 designated;\n}\n\n/// The incoming and outgoing flows of an account. Fits in 32 bytes to minimize\n/// storage costs.\nstruct Flow {\n /// Rate of outgoing tokens\n TokensPerSecond outgoing;\n /// Rate of incoming tokens\n TokensPerSecond incoming;\n /// Last time that the flow was updated\n Timestamp updated;\n}\n\nlibrary Accounts {\n using Accounts for Account;\n using TokenFlows for TokensPerSecond;\n using Timestamps for Timestamp;\n\n /// Creates an account id from the account holder address and a discriminator.\n /// The discriminiator can be used to create different accounts that belong to\n /// the same account holder.\n function encodeId(\n address holder,\n bytes12 discriminator\n ) internal pure returns (AccountId) {\n bytes32 left = bytes32(bytes20(holder));\n bytes32 right = bytes32(uint256(uint96(discriminator)));\n return AccountId.wrap(left | right);\n }\n\n /// Extracts the account holder and the discriminator from the the account id\n function decodeId(AccountId id) internal pure returns (address, bytes12) {\n bytes32 unwrapped = AccountId.unwrap(id);\n address holder = address(bytes20(unwrapped));\n bytes12 discriminator = bytes12(uint96(uint256(unwrapped)));\n return (holder, discriminator);\n }\n\n /// Calculates whether the available balance is sufficient to sustain the\n /// outgoing flow of tokens until the specified timestamp\n function isSolventAt(\n Account memory account,\n Timestamp timestamp\n ) internal pure returns (bool) {\n Duration duration = account.flow.updated.until(timestamp);\n uint128 outgoing = account.flow.outgoing.accumulate(duration);\n return outgoing <= account.balance.available;\n }\n\n /// Updates the available and designated balances by accumulating the\n /// outgoing and incoming flows up until the specified timestamp. Outgoing\n /// tokens are deducted from the available balance. Incoming tokens are added\n /// to the designated tokens.\n function accumulateFlows(\n Account memory account,\n Timestamp timestamp\n ) internal pure {\n Duration duration = account.flow.updated.until(timestamp);\n account.balance.available -= account.flow.outgoing.accumulate(duration);\n account.balance.designated += account.flow.incoming.accumulate(duration);\n account.flow.updated = timestamp;\n }\n\n /// Starts an incoming flow of tokens at the specified rate. If there already\n /// is a flow of incoming tokens, then its rate is increased accordingly.\n function flowIn(Account memory account, TokensPerSecond rate) internal view {\n account.accumulateFlows(Timestamps.currentTime());\n account.flow.incoming = account.flow.incoming + rate;\n }\n\n /// Starts an outgoing flow of tokens at the specified rate. If there is\n /// already a flow of incoming tokens, then these are used to pay for the\n /// outgoing flow. If there are insuffient incoming tokens, then the outgoing\n /// rate is increased.\n function flowOut(Account memory account, TokensPerSecond rate) internal view {\n account.accumulateFlows(Timestamps.currentTime());\n if (rate <= account.flow.incoming) {\n account.flow.incoming = account.flow.incoming - rate;\n } else {\n account.flow.outgoing = account.flow.outgoing + rate;\n account.flow.outgoing = account.flow.outgoing - account.flow.incoming;\n account.flow.incoming = TokensPerSecond.wrap(0);\n }\n }\n}\n" }, "contracts/vault/Funds.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"./Timestamps.sol\";\n\nstruct Fund {\n /// The time-lock unlocks at this time\n Timestamp lockExpiry;\n /// The lock expiry can be extended no further than this\n Timestamp lockMaximum;\n /// Indicates whether fund is frozen, and at what time\n Timestamp frozenAt;\n}\n\n/// A fund can go through the following states:\n///\n/// --> Inactive ---> Locked -----> Withdrawing\n/// \\ ^\n/// \\ /\n/// --> Frozen --\n///\nenum FundStatus {\n /// Indicates that the fund is inactive and contains no tokens. This is the\n /// initial state.\n Inactive,\n /// Indicates that a time-lock is set and withdrawing tokens is not allowed. A\n /// fund needs to be locked for deposits, transfers, flows and burning to be\n /// allowed.\n Locked,\n /// Indicates that a locked fund is frozen. Flows have stopped, nothing is\n /// allowed until the fund unlocks.\n Frozen,\n /// Indicates the fund has unlocked and withdrawing is allowed. Other\n /// operations are no longer allowed.\n Withdrawing\n}\n\nlibrary Funds {\n function status(Fund memory fund) internal view returns (FundStatus) {\n if (Timestamps.currentTime() < fund.lockExpiry) {\n if (fund.frozenAt != Timestamp.wrap(0)) {\n return FundStatus.Frozen;\n }\n return FundStatus.Locked;\n }\n if (fund.lockMaximum == Timestamp.wrap(0)) {\n return FundStatus.Inactive;\n }\n return FundStatus.Withdrawing;\n }\n\n function flowEnd(Fund memory fund) internal pure returns (Timestamp) {\n if (fund.frozenAt != Timestamp.wrap(0)) {\n return fund.frozenAt;\n }\n return fund.lockExpiry;\n }\n}\n" }, "contracts/vault/Timestamps.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/// Represents a moment in time, represented as unix time (number of seconds\n/// since 1970). Uses a uint40 to facilitate efficient packing in structs. A\n/// uint40 allows times to be represented for the coming 30 000 years.\ntype Timestamp is uint40;\n/// Represents a duration of time in seconds\ntype Duration is uint40;\n\nusing {_timestampEquals as ==} for Timestamp global;\nusing {_timestampNotEqual as !=} for Timestamp global;\nusing {_timestampLessThan as <} for Timestamp global;\nusing {_timestampAtMost as <=} for Timestamp global;\n\nfunction _timestampEquals(Timestamp a, Timestamp b) pure returns (bool) {\n return Timestamp.unwrap(a) == Timestamp.unwrap(b);\n}\n\nfunction _timestampNotEqual(Timestamp a, Timestamp b) pure returns (bool) {\n return Timestamp.unwrap(a) != Timestamp.unwrap(b);\n}\n\nfunction _timestampLessThan(Timestamp a, Timestamp b) pure returns (bool) {\n return Timestamp.unwrap(a) < Timestamp.unwrap(b);\n}\n\nfunction _timestampAtMost(Timestamp a, Timestamp b) pure returns (bool) {\n return Timestamp.unwrap(a) <= Timestamp.unwrap(b);\n}\n\nlibrary Timestamps {\n /// Returns the current block timestamp converted to a Timestamp type\n function currentTime() internal view returns (Timestamp) {\n return Timestamp.wrap(uint40(block.timestamp));\n }\n\n /// Calculates the duration from start until end\n function until(\n Timestamp start,\n Timestamp end\n ) internal pure returns (Duration) {\n return Duration.wrap(Timestamp.unwrap(end) - Timestamp.unwrap(start));\n }\n}\n" }, "contracts/vault/TokenFlows.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"./Timestamps.sol\";\n\n/// Represents a flow of tokens. Uses a uint96 to represent the flow rate, which\n/// should be more than enough. Given a standard 18 decimal places for the\n/// ERC20 token, this still allows for a rate of 10^10 whole coins per second.\ntype TokensPerSecond is uint96;\n\nusing {_tokensPerSecondMinus as -} for TokensPerSecond global;\nusing {_tokensPerSecondPlus as +} for TokensPerSecond global;\nusing {_tokensPerSecondEquals as ==} for TokensPerSecond global;\nusing {_tokensPerSecondAtMost as <=} for TokensPerSecond global;\n\nfunction _tokensPerSecondMinus(\n TokensPerSecond a,\n TokensPerSecond b\n) pure returns (TokensPerSecond) {\n return\n TokensPerSecond.wrap(TokensPerSecond.unwrap(a) - TokensPerSecond.unwrap(b));\n}\n\nfunction _tokensPerSecondPlus(\n TokensPerSecond a,\n TokensPerSecond b\n) pure returns (TokensPerSecond) {\n return\n TokensPerSecond.wrap(TokensPerSecond.unwrap(a) + TokensPerSecond.unwrap(b));\n}\n\nfunction _tokensPerSecondEquals(\n TokensPerSecond a,\n TokensPerSecond b\n) pure returns (bool) {\n return TokensPerSecond.unwrap(a) == TokensPerSecond.unwrap(b);\n}\n\nfunction _tokensPerSecondAtMost(\n TokensPerSecond a,\n TokensPerSecond b\n) pure returns (bool) {\n return TokensPerSecond.unwrap(a) <= TokensPerSecond.unwrap(b);\n}\n\nlibrary TokenFlows {\n /// Calculates how many tokens are accumulated when a token flow is maintained\n /// for a duration of time.\n function accumulate(\n TokensPerSecond rate,\n Duration duration\n ) internal pure returns (uint128) {\n return uint128(TokensPerSecond.unwrap(rate)) * Duration.unwrap(duration);\n }\n}\n" }, "contracts/vault/VaultBase.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./Accounts.sol\";\nimport \"./Funds.sol\";\n\n/// Records account balances and token flows. Accounts are separated into funds.\n/// Funds are kept separate between controllers.\n///\n/// A fund can only be manipulated by a controller when it is locked. Tokens can\n/// only be withdrawn when a fund is unlocked.\n///\n/// The vault maintains a number of invariants to ensure its integrity.\n///\n/// The lock invariant ensures that there is a maximum time that a fund can be\n/// locked:\n///\n/// (∀ controller ∈ Controller, fundId ∈ FundId:\n/// fund.lockExpiry <= fund.lockMaximum\n/// where fund = _funds[controller][fundId])\n///\n/// The account invariant ensures that the outgoing token flow can be sustained\n/// for the maximum time that a fund can be locked:\n///\n/// (∀ controller ∈ Controller, fundId ∈ FundId, accountId ∈ AccountId:\n/// flow.outgoing * (fund.lockMaximum - flow.updated) <= balance.available\n/// where fund = _funds[controller][fundId])\n/// and flow = _accounts[controller][fundId][accountId].flow\n/// and balance = _accounts[controller][fundId][accountId].balance\n///\n/// The flow invariant ensures that incoming and outgoing flow rates match:\n///\n/// (∀ controller ∈ Controller, fundId ∈ FundId:\n/// (∑ accountId ∈ AccountId: accounts[accountId].flow.incoming) =\n/// (∑ accountId ∈ AccountId: accounts[accountId].flow.outgoing)\n/// where accounts = _accounts[controller][fundId])\n///\nabstract contract VaultBase {\n using SafeERC20 for IERC20;\n using Accounts for Account;\n using Funds for Fund;\n\n IERC20 internal immutable _token;\n\n /// Represents a smart contract that can redistribute and burn tokens in funds\n type Controller is address;\n /// Unique identifier for a fund, chosen by the controller\n type FundId is bytes32;\n\n /// Each controller has its own set of funds\n mapping(Controller => mapping(FundId => Fund)) private _funds;\n /// Each account holder has its own set of accounts in a fund\n mapping(Controller => mapping(FundId => mapping(AccountId => Account)))\n private _accounts;\n\n constructor(IERC20 token) {\n _token = token;\n }\n\n function _getFundStatus(\n Controller controller,\n FundId fundId\n ) internal view returns (FundStatus) {\n return _funds[controller][fundId].status();\n }\n\n function _getLockExpiry(\n Controller controller,\n FundId fundId\n ) internal view returns (Timestamp) {\n return _funds[controller][fundId].lockExpiry;\n }\n\n function _getBalance(\n Controller controller,\n FundId fundId,\n AccountId accountId\n ) internal view returns (Balance memory) {\n Fund memory fund = _funds[controller][fundId];\n FundStatus status = fund.status();\n if (status == FundStatus.Locked) {\n Account memory account = _accounts[controller][fundId][accountId];\n account.accumulateFlows(Timestamps.currentTime());\n return account.balance;\n }\n if (status == FundStatus.Withdrawing || status == FundStatus.Frozen) {\n Account memory account = _accounts[controller][fundId][accountId];\n account.accumulateFlows(fund.flowEnd());\n return account.balance;\n }\n return Balance({available: 0, designated: 0});\n }\n\n function _lock(\n Controller controller,\n FundId fundId,\n Timestamp expiry,\n Timestamp maximum\n ) internal {\n Fund memory fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Inactive, VaultFundAlreadyLocked());\n fund.lockExpiry = expiry;\n fund.lockMaximum = maximum;\n _checkLockInvariant(fund);\n _funds[controller][fundId] = fund;\n }\n\n function _extendLock(\n Controller controller,\n FundId fundId,\n Timestamp expiry\n ) internal {\n Fund memory fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n require(fund.lockExpiry <= expiry, VaultInvalidExpiry());\n fund.lockExpiry = expiry;\n _checkLockInvariant(fund);\n _funds[controller][fundId] = fund;\n }\n\n function _deposit(\n Controller controller,\n FundId fundId,\n AccountId accountId,\n uint128 amount\n ) internal {\n Fund storage fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n\n Account storage account = _accounts[controller][fundId][accountId];\n\n account.balance.available += amount;\n\n _token.safeTransferFrom(\n Controller.unwrap(controller),\n address(this),\n amount\n );\n }\n\n function _designate(\n Controller controller,\n FundId fundId,\n AccountId accountId,\n uint128 amount\n ) internal {\n Fund memory fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n\n Account memory account = _accounts[controller][fundId][accountId];\n require(amount <= account.balance.available, VaultInsufficientBalance());\n\n account.balance.available -= amount;\n account.balance.designated += amount;\n _checkAccountInvariant(account, fund);\n\n _accounts[controller][fundId][accountId] = account;\n }\n\n function _transfer(\n Controller controller,\n FundId fundId,\n AccountId from,\n AccountId to,\n uint128 amount\n ) internal {\n Fund memory fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n\n Account memory sender = _accounts[controller][fundId][from];\n require(amount <= sender.balance.available, VaultInsufficientBalance());\n\n sender.balance.available -= amount;\n _checkAccountInvariant(sender, fund);\n\n _accounts[controller][fundId][from] = sender;\n\n _accounts[controller][fundId][to].balance.available += amount;\n }\n\n function _flow(\n Controller controller,\n FundId fundId,\n AccountId from,\n AccountId to,\n TokensPerSecond rate\n ) internal {\n Fund memory fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n\n Account memory sender = _accounts[controller][fundId][from];\n sender.flowOut(rate);\n _checkAccountInvariant(sender, fund);\n _accounts[controller][fundId][from] = sender;\n\n Account memory receiver = _accounts[controller][fundId][to];\n receiver.flowIn(rate);\n _accounts[controller][fundId][to] = receiver;\n }\n\n function _burnDesignated(\n Controller controller,\n FundId fundId,\n AccountId accountId,\n uint128 amount\n ) internal {\n Fund storage fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n\n Account storage account = _accounts[controller][fundId][accountId];\n require(account.balance.designated >= amount, VaultInsufficientBalance());\n\n account.balance.designated -= amount;\n\n _token.safeTransfer(address(0xdead), amount);\n }\n\n function _burnAccount(\n Controller controller,\n FundId fundId,\n AccountId accountId\n ) internal {\n Fund storage fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n\n Account memory account = _accounts[controller][fundId][accountId];\n require(account.flow.incoming == account.flow.outgoing, VaultFlowNotZero());\n uint128 amount = account.balance.available + account.balance.designated;\n\n delete _accounts[controller][fundId][accountId];\n\n _token.safeTransfer(address(0xdead), amount);\n }\n\n function _freezeFund(Controller controller, FundId fundId) internal {\n Fund storage fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Locked, VaultFundNotLocked());\n\n fund.frozenAt = Timestamps.currentTime();\n }\n\n function _withdraw(\n Controller controller,\n FundId fundId,\n AccountId accountId\n ) internal {\n Fund memory fund = _funds[controller][fundId];\n require(fund.status() == FundStatus.Withdrawing, VaultFundNotUnlocked());\n\n Account memory account = _accounts[controller][fundId][accountId];\n account.accumulateFlows(fund.flowEnd());\n uint128 amount = account.balance.available + account.balance.designated;\n\n delete _accounts[controller][fundId][accountId];\n\n (address owner, ) = Accounts.decodeId(accountId);\n _token.safeTransfer(owner, amount);\n }\n\n function _checkLockInvariant(Fund memory fund) private pure {\n require(fund.lockExpiry <= fund.lockMaximum, VaultInvalidExpiry());\n }\n\n function _checkAccountInvariant(\n Account memory account,\n Fund memory fund\n ) private pure {\n require(account.isSolventAt(fund.lockMaximum), VaultInsufficientBalance());\n }\n\n error VaultInsufficientBalance();\n error VaultInvalidExpiry();\n error VaultFundNotLocked();\n error VaultFundNotUnlocked();\n error VaultFundAlreadyLocked();\n error VaultFlowNotZero();\n}\n" } }, "settings": { "evmVersion": "paris", "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "devdoc", "userdoc", "storageLayout", "evm.gasEstimates" ], "": [ "ast" ] } }, "metadata": { "useLiteralContent": true } } }