Contract Name:
GameItemsMock
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;
/**
* @title The ERC-2771 Recipient Base Abstract Class - Declarations
*
* @notice A contract must implement this interface in order to support relayed transaction.
*
* @notice It is recommended that your contract inherits from the ERC2771Recipient contract.
*/
abstract contract IERC2771Recipient {
/**
* :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
* @param forwarder The address of the Forwarder contract that is being used.
* @return isTrustedForwarder `true` if the Forwarder is trusted to forward relayed transactions by this Recipient.
*/
function isTrustedForwarder(address forwarder) public virtual view returns(bool);
/**
* @notice Use this method the contract anywhere instead of msg.sender to support relayed transactions.
* @return sender The real sender of this call.
* For a call that came through the Forwarder the real sender is extracted from the last 20 bytes of the `msg.data`.
* Otherwise simply returns `msg.sender`.
*/
function _msgSender() internal virtual view returns (address);
/**
* @notice Use this method in the contract instead of `msg.data` when difference matters (hashing, signature, etc.)
* @return data The real `msg.data` of this call.
* For a call that came through the Forwarder, the real sender address was appended as the last 20 bytes
* of the `msg.data` - so this method will strip those 20 bytes off.
* Otherwise (if the call was made directly and not through the forwarder) simply returns `msg.data`.
*/
function _msgData() internal virtual view returns (bytes calldata);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// Mapping from token ID to account balances
mapping(uint256 => mapping(address => uint256)) private _balances;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `amount` tokens of token type `id`.
*/
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;
import "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
// Used for calculating decimal-point percentages (10000 = 100%)
uint256 constant PERCENTAGE_RANGE = 10000;
// Pauser Role - Can pause the game
bytes32 constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
// Minter Role - Can mint items, NFTs, and ERC20 currency
bytes32 constant MINTER_ROLE = keccak256("MINTER_ROLE");
// Manager Role - Can manage the shop, loot tables, and other game data
bytes32 constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
// Game Logic Contract - Contract that executes game logic and accesses other systems
bytes32 constant GAME_LOGIC_CONTRACT_ROLE = keccak256(
"GAME_LOGIC_CONTRACT_ROLE"
);
// Game Currency Contract - Allowlisted currency ERC20 contract
bytes32 constant GAME_CURRENCY_CONTRACT_ROLE = keccak256(
"GAME_CURRENCY_CONTRACT_ROLE"
);
// Game NFT Contract - Allowlisted game NFT ERC721 contract
bytes32 constant GAME_NFT_CONTRACT_ROLE = keccak256("GAME_NFT_CONTRACT_ROLE");
// Game Items Contract - Allowlist game items ERC1155 contract
bytes32 constant GAME_ITEMS_CONTRACT_ROLE = keccak256(
"GAME_ITEMS_CONTRACT_ROLE"
);
// Depositor role - used by Polygon bridge to mint on child chain
bytes32 constant DEPOSITOR_ROLE = keccak256("DEPOSITOR_ROLE");
// Randomizer role - Used by the randomizer contract to callback
bytes32 constant RANDOMIZER_ROLE = keccak256("RANDOMIZER_ROLE");
// Trusted forwarder role - Used by meta transactions to verify trusted forwader(s)
bytes32 constant TRUSTED_FORWARDER_ROLE = keccak256("TRUSTED_FORWARDER_ROLE");
// =====
// All of the possible traits in the system
// =====
// Generation of a token
uint256 constant GENERATION_TRAIT_ID = uint256(keccak256("generation"));
// XP for a token
uint256 constant XP_TRAIT_ID = uint256(keccak256("xp"));
// Current level of a token
uint256 constant LEVEL_TRAIT_ID = uint256(keccak256("level"));
// Whether or not a token is a pirate
uint256 constant IS_PIRATE_TRAIT_ID = uint256(keccak256("is_pirate"));
// Rank of the ship
uint256 constant SHIP_RANK_TRAIT_ID = uint256(keccak256("ship_rank"));
// Image hash of token's image, used for verifiable / fair drops
uint256 constant IMAGE_HASH_TRAIT_ID = uint256(keccak256("image_hash"));
// Name of a token
uint256 constant NAME_TRAIT_ID = uint256(keccak256("name_trait"));
// Description of a token
uint256 constant DESCRIPTION_TRAIT_ID = uint256(keccak256("description_trait"));
// General rarity for a token (corresponds to IGameRarity)
uint256 constant RARITY_TRAIT_ID = uint256(keccak256("rarity"));
// The character's affinity for a specific element
uint256 constant ELEMENTAL_AFFINITY_TRAIT_ID = uint256(
keccak256("elemental_affinity")
);
// The character's dice rolls
uint256 constant DICE_ROLL_1_TRAIT_ID = uint256(keccak256("dice_roll_1"));
uint256 constant DICE_ROLL_2_TRAIT_ID = uint256(keccak256("dice_roll_2"));
// The character's star sign (astrology)
uint256 constant STAR_SIGN_TRAIT_ID = uint256(keccak256("star_sign"));
// Image for the token
uint256 constant IMAGE_TRAIT_ID = uint256(keccak256("image_trait"));
// How much energy the token provides if used
uint256 constant ENERGY_PROVIDED_TRAIT_ID = uint256(
keccak256("energy_provided")
);
// Whether a given token is soulbound, meaning it is unable to be transferred
uint256 constant SOULBOUND_TRAIT_ID = uint256(keccak256("soulbound"));
// ------
// Avatar Profile Picture related traits
// If an avatar is a 1 of 1, this is their only trait
uint256 constant PROFILE_IS_LEGENDARY_TRAIT_ID = uint256(
keccak256("profile_is_legendary")
);
// Avatar's archetype -- possible values: Human (including Druid, Mage, Berserker, Crusty), Robot, Animal, Zombie, Vampire, Ghost
uint256 constant PROFILE_CHARACTER_TYPE = uint256(
keccak256("profile_character_type")
);
// Avatar's profile picture's background image
uint256 constant PROFILE_BACKGROUND_TRAIT_ID = uint256(
keccak256("profile_background")
);
// Avatar's eye style
uint256 constant PROFILE_EYES_TRAIT_ID = uint256(keccak256("profile_eyes"));
// Avatar's facial hair type
uint256 constant PROFILE_FACIAL_HAIR_TRAIT_ID = uint256(
keccak256("profile_facial_hair")
);
// Avatar's hair style
uint256 constant PROFILE_HAIR_TRAIT_ID = uint256(keccak256("profile_hair"));
// Avatar's skin color
uint256 constant PROFILE_SKIN_TRAIT_ID = uint256(keccak256("profile_skin"));
// Avatar's coat color
uint256 constant PROFILE_COAT_TRAIT_ID = uint256(keccak256("profile_coat"));
// Avatar's earring(s) type
uint256 constant PROFILE_EARRING_TRAIT_ID = uint256(
keccak256("profile_facial_hair")
);
// Avatar's eye covering
uint256 constant PROFILE_EYE_COVERING_TRAIT_ID = uint256(
keccak256("profile_eye_covering")
);
// Avatar's headwear
uint256 constant PROFILE_HEADWEAR_TRAIT_ID = uint256(
keccak256("profile_headwear")
);
// Avatar's (Mages only) gem color
uint256 constant PROFILE_MAGE_GEM_TRAIT_ID = uint256(
keccak256("profile_mage_gem")
);
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@opengsn/contracts/src/interfaces/IERC2771Recipient.sol";
import {IGameRegistry} from "./interfaces/IGameRegistry.sol";
import {ISystem} from "./interfaces/ISystem.sol";
import {TRUSTED_FORWARDER_ROLE} from "./Constants.sol";
import {ITraitsProvider, ID as TRAITS_PROVIDER_ID} from "./interfaces/ITraitsProvider.sol";
import {ILockingSystem, ID as LOCKING_SYSTEM_ID} from "./locking/ILockingSystem.sol";
import {IRandomizer, IRandomizerCallback, ID as RANDOMIZER_ID} from "./randomizer/IRandomizer.sol";
import {ILootSystem, ID as LOOT_SYSTEM_ID} from "./loot/ILootSystem.sol";
/** @title Contract that lets a child contract access the GameRegistry contract */
abstract contract GameRegistryConsumer is
ISystem,
Ownable,
IERC2771Recipient,
IRandomizerCallback
{
/// @notice Whether or not the contract is paused
bool private _paused;
/// @notice Id for the system/component
uint256 private _id;
/// @notice Read access contract
IGameRegistry private _gameRegistry;
/** EVENTS **/
/// @dev Emitted when the pause is triggered by `account`.
event Paused(address account);
/// @dev Emitted when the pause is lifted by `account`.
event Unpaused(address account);
/** ERRORS **/
/// @notice Not authorized to perform action
error MissingRole(address account, bytes32 expectedRole);
/** MODIFIERS **/
// Modifier to verify a user has the appropriate role to call a given function
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/** ERRORS **/
/// @notice gameRegistryAddress does not implement IGameRegistry
error InvalidGameRegistry();
/** SETUP **/
/** Sets the GameRegistry contract address for this contract */
constructor(address gameRegistryAddress, uint256 id) {
_gameRegistry = IGameRegistry(gameRegistryAddress);
_id = id;
if (gameRegistryAddress == address(0)) {
revert InvalidGameRegistry();
}
_paused = true;
}
/** EXTERNAL **/
/** @return ID for this system */
function getId() public view override returns (uint256) {
return _id;
}
/**
* Pause/Unpause the contract
*
* @param shouldPause Whether or pause or unpause
*/
function setPaused(bool shouldPause) external onlyOwner {
if (shouldPause) {
_pause();
} else {
_unpause();
}
}
/**
* @dev Returns true if the contract OR the GameRegistry is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused || _gameRegistry.paused();
}
/**
* Sets the GameRegistry contract address for this contract
*
* @param gameRegistryAddress Address for the GameRegistry contract
*/
function setGameRegistry(address gameRegistryAddress) external onlyOwner {
_gameRegistry = IGameRegistry(gameRegistryAddress);
if (gameRegistryAddress == address(0)) {
revert InvalidGameRegistry();
}
}
/** @return GameRegistry contract for this contract */
function getGameRegistry() external view returns (IGameRegistry) {
return _gameRegistry;
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function _hasAccessRole(bytes32 role, address account)
internal
view
returns (bool)
{
return _gameRegistry.hasAccessRole(role, account);
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view {
if (!_gameRegistry.hasAccessRole(role, account)) {
revert MissingRole(account, role);
}
}
/** Returns the traits provider for this contract */
function _traitsProvider() internal view returns (ITraitsProvider) {
return ITraitsProvider(_getSystem(TRAITS_PROVIDER_ID));
}
/** @return Interface to the LockingSystem */
function _lockingSystem() internal view returns (ILockingSystem) {
return ILockingSystem(_gameRegistry.getSystem(LOCKING_SYSTEM_ID));
}
/** @return Interface to the LootSystem */
function _lootSystem() internal view returns (ILootSystem) {
return ILootSystem(_gameRegistry.getSystem(LOOT_SYSTEM_ID));
}
/** @return Interface to the Randomizer */
function _randomizer() internal view returns (IRandomizer) {
return IRandomizer(_gameRegistry.getSystem(RANDOMIZER_ID));
}
/** @return Address for a given system */
function _getSystem(uint256 systemId) internal view returns (address) {
return _gameRegistry.getSystem(systemId);
}
/**
* Requests randomness from the game's Randomizer contract
*
* @param numWords Number of words to request from the VRF
*
* @return Id of the randomness request
*/
function _requestRandomWords(uint32 numWords) internal returns (uint256) {
return
_randomizer().requestRandomWords(
IRandomizerCallback(this),
numWords
);
}
/**
* Callback for when a random number request has returned with random words
*
* @param requestId Id of the request
* @param randomWords Random words
*/
function fulfillRandomWordsCallback(
uint256 requestId,
uint256[] memory randomWords
) external virtual override {
// Do nothing by default
}
/**
* Returns the Player address for the Operator account
* @param operatorAccount address of the Operator account to retrieve the player for
*/
function _getPlayerAccount(address operatorAccount)
internal
view
returns (address playerAccount)
{
return _gameRegistry.getPlayerAccount(operatorAccount);
}
/// @inheritdoc IERC2771Recipient
function isTrustedForwarder(address forwarder)
public
view
virtual
override
returns (bool)
{
return
address(_gameRegistry) != address(0) &&
_hasAccessRole(TRUSTED_FORWARDER_ROLE, forwarder);
}
/** INTERNAL **/
/// @inheritdoc IERC2771Recipient
function _msgSender()
internal
view
virtual
override(Context, IERC2771Recipient)
returns (address ret)
{
if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
assembly {
ret := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
ret = msg.sender;
}
}
/// @inheritdoc IERC2771Recipient
function _msgData()
internal
view
virtual
override(Context, IERC2771Recipient)
returns (bytes calldata ret)
{
if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
return msg.data[0:msg.data.length - 20];
} else {
return msg.data;
}
}
/** PAUSABLE **/
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual {
require(_paused == false, "Pausable: not paused");
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual {
require(_paused == true, "Pausable: not paused");
_paused = false;
emit Unpaused(_msgSender());
}
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {GAME_LOGIC_CONTRACT_ROLE, NAME_TRAIT_ID, DESCRIPTION_TRAIT_ID, IMAGE_TRAIT_ID} from "./Constants.sol";
import {ITraitsConsumer} from "./interfaces/ITraitsConsumer.sol";
import {ITokenURIHandler} from "./tokens/ITokenURIHandler.sol";
import {GameRegistryConsumer} from "./GameRegistryConsumer.sol";
/** @title Contract that lets a child contract access the TraitsProvider contract */
abstract contract TraitsConsumer is
ITraitsConsumer,
GameRegistryConsumer,
IERC165
{
using Strings for uint256;
/// @notice Override URI for the NFT contract. If not set, on-chain data is used instead
string public _overrideURI;
/// @notice Pointer to the handler for TokenURI calls
address public tokenURIHandler;
/// @notice Base URI for images, tokenId is appended to make final uri
string public _baseImageURI;
/// @notice Base URI for external link, tokenId is appended to make final uri
string public _baseExternalURI;
/// @notice Default image URI for the token
/// @dev Should be set in the constructor
string public _defaultImageURI;
/// @notice Default description for the token
string public _defaultDescription;
/** ERRORS */
/// @notice traitsProviderAddress does not implement ITraitsProvvider
error InvalidTraitsProvider();
/** SETUP **/
/** Set game registry */
constructor(address _gameRegistryAddress, uint256 _id)
GameRegistryConsumer(_gameRegistryAddress, _id)
{}
/** Sets the override URI for the tokens */
function setURI(string calldata newURI) external onlyOwner {
_overrideURI = newURI;
}
/** Sets base image URI for the tokens */
function setBaseImageURI(string calldata newURI) external onlyOwner {
_baseImageURI = newURI;
}
/** Sets base external URI for the tokens */
function setBaseExternalURI(string calldata newURI) external onlyOwner {
_baseExternalURI = newURI;
}
/** @return Token name for the given tokenId */
function tokenName(uint256 tokenId)
external
view
virtual
override
returns (string memory)
{
if (_hasTrait(tokenId, NAME_TRAIT_ID)) {
// If token has a name trait set, use that
return _getTraitString(tokenId, NAME_TRAIT_ID);
} else {
return string(abi.encodePacked("#", tokenId.toString()));
}
}
/** @return Token name for the given tokenId */
function tokenDescription(uint256 tokenId)
external
view
virtual
override
returns (string memory)
{
if (_hasTrait(tokenId, DESCRIPTION_TRAIT_ID)) {
// If token has a description trait set, use that
return _getTraitString(tokenId, DESCRIPTION_TRAIT_ID);
}
return _defaultDescription;
}
/** @return Image URI for the given tokenId */
function imageURI(uint256 tokenId)
external
view
virtual
override
returns (string memory)
{
if (_hasTrait(tokenId, IMAGE_TRAIT_ID)) {
// If token has a description trait set, use that
return _getTraitString(tokenId, IMAGE_TRAIT_ID);
}
if (bytes(_baseImageURI).length > 0) {
return string(abi.encodePacked(_baseImageURI, tokenId.toString()));
}
return _defaultImageURI;
}
/** @return External URI for the given tokenId */
function externalURI(uint256 tokenId)
external
view
virtual
override
returns (string memory)
{
if (bytes(_baseExternalURI).length > 0) {
return
string(abi.encodePacked(_baseExternalURI, tokenId.toString()));
}
return "";
}
/**
* Sets the tokenURI handler for this token
*
* @param handler Address of the handler contract to use
*/
function setTokenURIHandler(address handler) external onlyOwner {
tokenURIHandler = handler;
}
/** INTERNAL **/
/**
* @param tokenId Id of the token to get a trait value for
* @param traitId Id of the trait to get the value for
*
* @return Trait int256 value for the given token and trait
*/
function _getTraitInt256(uint256 tokenId, uint256 traitId)
internal
view
returns (int256)
{
return
_traitsProvider().getTraitInt256(address(this), tokenId, traitId);
}
/**
* @param tokenId Id of the token to get a trait value for
* @param traitId Id of the trait to get the value for
*
* @return Trait string value for the given token and trait
*/
function _getTraitString(uint256 tokenId, uint256 traitId)
internal
view
returns (string memory)
{
return
_traitsProvider().getTraitString(address(this), tokenId, traitId);
}
/**
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to retrieve
*
* @return Whether or not the token has the trait
*/
function _hasTrait(uint256 tokenId, uint256 traitId)
internal
view
returns (bool)
{
return _traitsProvider().hasTrait(address(this), tokenId, traitId);
}
/**
* Sets the int256 trait value for this token
*
* @param tokenId Id of the token to set trait for
* @param traitId Id of the trait to set
* @param value New value of the trait
*/
function _setTraitInt256(
uint256 tokenId,
uint256 traitId,
int256 value
) internal {
_traitsProvider().setTraitInt256(
address(this),
tokenId,
traitId,
value
);
}
/**
* Sets the string trait value for this token
*
* @param tokenId Id of the token to set trait for
* @param traitId Id of the trait to set
* @param value New value of the trait
*/
function _setTraitString(
uint256 tokenId,
uint256 traitId,
string memory value
) internal {
_traitsProvider().setTraitString(
address(this),
tokenId,
traitId,
value
);
}
/**
* @notice Generates metadata for the given tokenId
* @param tokenId Token to generate metadata for
* @return A base64 encoded JSON metadata string
*/
function _tokenURI(uint256 tokenId)
internal
view
virtual
returns (string memory)
{
// If override URI is set, return the URI with tokenId appended instead of on-chain data
if (bytes(_overrideURI).length > 0) {
return string(abi.encodePacked(_overrideURI, tokenId.toString()));
}
if (tokenURIHandler == address(0)) {
return "";
}
return
ITokenURIHandler(tokenURIHandler).tokenURI(
_msgSender(),
address(this),
tokenId
);
}
/**
* @inheritdoc IERC165
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return
interfaceId == type(ITraitsConsumer).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
// @title Interface the game's ACL / Management Layer
interface IGameRegistry is IERC165 {
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasAccessRole(bytes32 role, address account)
external
view
returns (bool);
/** @return Whether or not the registry is paused */
function paused() external view returns (bool);
/**
* Registers a system by id
*
* @param systemId Id of the system
* @param systemAddress Address of the system contract
*/
function registerSystem(uint256 systemId, address systemAddress) external;
/** @return System based on an id */
function getSystem(uint256 systemId) external view returns (address);
/** @return Authorized Player account for an address
* @param operatorAddress Address of the Operator account
*/
function getPlayerAccount(address operatorAddress)
external
view
returns (address);
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* Defines a system the game engine
*/
interface ISystem {
/** @return The ID for the system. Ex: a uint256 casted keccak256 hash */
function getId() external view returns (uint256);
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import {ITraitsProvider} from "./ITraitsProvider.sol";
/** @title Consumer of traits, exposes functions to get traits for this contract */
interface ITraitsConsumer {
/** @return Token name for the given tokenId */
function tokenName(uint256 tokenId) external view returns (string memory);
/** @return Token name for the given tokenId */
function tokenDescription(uint256 tokenId)
external
view
returns (string memory);
/** @return Image URI for the given tokenId */
function imageURI(uint256 tokenId) external view returns (string memory);
/** @return External URI for the given tokenId */
function externalURI(uint256 tokenId) external view returns (string memory);
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
uint256 constant ID = uint256(keccak256("game.piratenation.traitsprovider"));
// Enum describing how the trait can be modified
enum TraitBehavior {
NOT_INITIALIZED, // Trait has not been initialized
UNRESTRICTED, // Trait can be changed unrestricted
IMMUTABLE, // Trait can only be set once and then never changed
INCREMENT_ONLY, // Trait can only be incremented
DECREMENT_ONLY // Trait can only be decremented
}
// Type of data to allow in the trait
enum TraitDataType {
NOT_INITIALIZED, // Trait has not been initialized
INT, // int256 data type
UINT, // uint128 data type
BOOL, // bool data type
STRING // string data type
}
// Holds metadata for a given trait type
struct TraitMetadata {
// Name of the trait, used in tokenURIs
string name;
// How the trait can be modified
TraitBehavior behavior;
// Trait type
TraitDataType dataType;
// Whether or not the trait is a top-level property and should not be in the attribute array
bool isTopLevelProperty;
}
// Used to pass traits around for URI generation
struct TokenURITrait {
string name;
bytes value;
TraitDataType dataType;
bool isTopLevelProperty;
}
/** @title Provides a set of traits to a set of ERC721/ERC1155 contracts */
interface ITraitsProvider is IERC165 {
/**
* Sets the raw abi-encoded value trait of a token, also checks to make sure trait can be modified
* @dev It's not recommended to use this versus a typed function as those provide type safety checks
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to modify
* @param value New value for the given trait
*/
function setTraitBytes(
address tokenContract,
uint256 tokenId,
uint256 traitId,
bytes calldata value
) external;
/**
* Sets several raw byte traits for a given token
* @dev It's not recommended to use this versus a typed function as those provide type safety checks
*
* @param tokenContract Address of the token's contract
* @param tokenIds Ids of the token to set traits for
* @param traitIds Ids of traits to set
* @param values Values of traits to set
*/
function batchSetTraitBytes(
address tokenContract,
uint256[] calldata tokenIds,
uint256[] calldata traitIds,
bytes[] calldata values
) external;
/**
* Sets the value for the string trait of a token, also checks to make sure trait can be modified
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to modify
* @param value New value for the given trait
*/
function setTraitString(
address tokenContract,
uint256 tokenId,
uint256 traitId,
string calldata value
) external;
/**
* Sets several string traits for a given token
*
* @param tokenContract Address of the token's contract
* @param tokenIds Ids of the token to set traits for
* @param traitIds Ids of traits to set
* @param values Values of traits to set
*/
function batchSetTraitString(
address tokenContract,
uint256[] calldata tokenIds,
uint256[] calldata traitIds,
string[] calldata values
) external;
/**
* Sets the value for the uint256 trait of a token, also checks to make sure trait can be modified
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to modify
* @param value New value for the given trait
*/
function setTraitUint256(
address tokenContract,
uint256 tokenId,
uint256 traitId,
uint256 value
) external;
/**
* Sets the value for the int256 trait of a token, also checks to make sure trait can be modified
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to modify
* @param value New value for the given trait
*/
function setTraitInt256(
address tokenContract,
uint256 tokenId,
uint256 traitId,
int256 value
) external;
/**
* Sets several int256 traits for a given token
*
* @param tokenContract Address of the token's contract
* @param tokenIds Ids of the token to set traits for
* @param traitIds Ids of traits to set
* @param values Values of traits to set
*/
function batchSetTraitInt256(
address tokenContract,
uint256[] calldata tokenIds,
uint256[] calldata traitIds,
int256[] calldata values
) external;
/**
* Sets the value for the bool trait of a token, also checks to make sure trait can be modified
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to modify
* @param value New value for the given trait
*/
function setTraitBool(
address tokenContract,
uint256 tokenId,
uint256 traitId,
bool value
) external;
/**
* Increments the trait for a token by the given amount
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to modify
* @param amount Amount to increment trait by
*/
function incrementTrait(
address tokenContract,
uint256 tokenId,
uint256 traitId,
uint256 amount
) external;
/**
* Decrements the trait for a token by the given amount
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to modify
* @param amount Amount to decrement trait by
*/
function decrementTrait(
address tokenContract,
uint256 tokenId,
uint256 traitId,
uint256 amount
) external;
/**
* Returns the trait data for a given token
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
*
* @return A struct containing all traits for the token
*/
function getTraitIds(address tokenContract, uint256 tokenId)
external
view
returns (uint256[] memory);
/**
* Retrieves a raw abi-encoded byte data for the given trait
*
* @param tokenContract Token contract (ERC721 or ERC1155)
* @param tokenId Id of the NFT or token type
* @param traitId Id of the trait to retrieve
*
* @return The value of the trait if it exists, reverts if the trait has not been set or is of a different type.
*/
function getTraitBytes(
address tokenContract,
uint256 tokenId,
uint256 traitId
) external view returns (bytes memory);
/**
* Retrieves a int256 trait for the given token
*
* @param tokenContract Token contract (ERC721 or ERC1155)
* @param tokenId Id of the NFT or token type
* @param traitId Id of the trait to retrieve
*
* @return The value of the trait if it exists, reverts if the trait has not been set or is of a different type.
*/
function getTraitInt256(
address tokenContract,
uint256 tokenId,
uint256 traitId
) external view returns (int256);
/**
* Retrieves a uint256 trait for the given token
*
* @param tokenContract Token contract (ERC721 or ERC1155)
* @param tokenId Id of the NFT or token type
* @param traitId Id of the trait to retrieve
*
* @return The value of the trait if it exists, reverts if the trait has not been set or is of a different type.
*/
function getTraitUint256(
address tokenContract,
uint256 tokenId,
uint256 traitId
) external view returns (uint256);
/**
* Retrieves a bool trait for the given token
*
* @param tokenContract Token contract (ERC721 or ERC1155)
* @param tokenId Id of the NFT or token type
* @param traitId Id of the trait to retrieve
*
* @return The value of the trait if it exists, reverts if the trait has not been set or is of a different type.
*/
function getTraitBool(
address tokenContract,
uint256 tokenId,
uint256 traitId
) external view returns (bool);
/**
* Retrieves a string trait for the given token
*
* @param tokenContract Token contract (ERC721 or ERC1155)
* @param tokenId Id of the NFT or token type
* @param traitId Id of the trait to retrieve
*
* @return The value of the trait if it exists, reverts if the trait has not been set or is of a different type.
*/
function getTraitString(
address tokenContract,
uint256 tokenId,
uint256 traitId
) external view returns (string memory);
/**
* Returns whether or not the given token has a trait
*
* @param tokenContract Address of the token's contract
* @param tokenId NFT tokenId or ERC1155 token type id
* @param traitId Id of the trait to retrieve
*
* @return Whether or not the token has the trait
*/
function hasTrait(
address tokenContract,
uint256 tokenId,
uint256 traitId
) external view returns (bool);
/**
* @param traitId Id of the trait to get metadata for
* @return Metadata for the given trait
*/
function getTraitMetadata(uint256 traitId)
external
view
returns (TraitMetadata memory);
/**
* Generate a tokenURI based on a set of global properties and traits
*
* @param tokenContract Address of the token contract
* @param tokenId Id of the token to generate traits for
*
* @return base64-encoded fully-formed tokenURI
*/
function generateTokenURI(
address tokenContract,
uint256 tokenId,
TokenURITrait[] memory extraTraits
) external view returns (string memory);
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
uint256 constant ID = uint256(keccak256("game.piratenation.lockingsystem"));
/// @title Interface for the LockingSystem that allows tokens to be locked by the game to prevent transfer
interface ILockingSystem is IERC165 {
/**
* Whether or not an NFT is locked
*
* @param tokenContract Token contract address
* @param tokenId Id of the token
*/
function isNFTLocked(address tokenContract, uint256 tokenId)
external
view
returns (bool);
/**
* Amount of token locked in the system by a given owner
*
* @param account Token owner
* @param tokenContract Token contract address
* @param tokenId Id of the token
*
* @return Number of tokens locked
*/
function itemAmountLocked(
address account,
address tokenContract,
uint256 tokenId
) external view returns (uint256);
/**
* Amount of tokens available for unlock
*
* @param account Token owner
* @param tokenContract Token contract address
* @param tokenId Id of the token
*
* @return Number of tokens locked
*/
function itemAmountUnlocked(
address account,
address tokenContract,
uint256 tokenId
) external view returns (uint256);
/**
* Whether or not the given items can be transferred
*
* @param account Token owner
* @param tokenContract Token contract address
* @param ids Ids of the tokens
* @param amounts Amounts of the tokens
*
* @return Whether or not the given items can be transferred
*/
function canTransferItems(
address account,
address tokenContract,
uint256[] memory ids,
uint256[] memory amounts
) external view returns (bool);
/**
* Lets the game add a reservation to a given NFT, this prevents the NFT from being unlocked
*
* @param tokenContract Token contract address
* @param tokenId Token id to reserve
* @param exclusive Whether or not the reservation is exclusive. Exclusive reservations prevent other reservations from using the tokens by removing them from the pool.
* @param data Data determined by the reserver, can be used to identify the source of the reservation for display in UI
*/
function addNFTReservation(
address tokenContract,
uint256 tokenId,
bool exclusive,
uint32 data
) external returns (uint32);
/**
* Lets the game remove a reservation from a given token
*
* @param tokenContract Token contract
* @param tokenId Id of the token
* @param reservationId Id of the reservation to remove
*/
function removeNFTReservation(
address tokenContract,
uint256 tokenId,
uint32 reservationId
) external;
/**
* Lets the game add a reservation to a given token, this prevents the token from being unlocked
*
* @param account Owner of the token to reserver
* @param tokenContract Token contract address
* @param tokenId Token id to reserve
* @param amount Number of tokens to reserve (1 for NFTs, >=1 for ERC1155)
* @param exclusive Whether or not the reservation is exclusive. Exclusive reservations prevent other reservations from using the tokens by removing them from the pool.
* @param data Data determined by the reserver, can be used to identify the source of the reservation for display in UI
*/
function addItemReservation(
address account,
address tokenContract,
uint256 tokenId,
uint256 amount,
bool exclusive,
uint32 data
) external returns (uint32);
/**
* Lets the game remove a reservation from a given token
*
* @param account Owner to remove reservation from
* @param tokenContract Token contract
* @param tokenId Id of the token
* @param reservationId Id of the reservation to remove
*/
function removeItemReservation(
address account,
address tokenContract,
uint256 tokenId,
uint32 reservationId
) external;
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
uint256 constant ID = uint256(keccak256("game.piratenation.lootsystem"));
/// @title Interface for the LootSystem that gives player loot (tokens, XP, etc) for playing the game
interface ILootSystem is IERC165 {
// Type of loot
enum LootType {
UNDEFINED,
ERC20,
ERC721,
ERC1155,
LOOT_TABLE
}
// Individual loot to grant
struct Loot {
// Type of fulfillment (ERC721, ERC1155, ERC20, LOOT_TABLE)
LootType lootType;
// Contract to grant tokens from
address tokenContract;
// Id of the token to grant (ERC1155/LOOT TABLE types only)
uint256 lootId;
// Amount of token to grant (XP, ERC20, ERC1155)
uint256 amount;
}
/**
* Grants the given user loot(s), calls VRF to ensure it's truly random
*
* @param to Address to grant loot to
* @param loots Loots to grant
*/
function grantLoot(address to, Loot[] calldata loots) external;
/**
* Grants the given user loot(s), calls VRF to ensure it's truly random
*
* @param to Address to grant loot to
* @param loots Loots to grant
* @param randomWord Optional random word to skip VRF callback if we already have words generated / are in a VRF callback
*/
function grantLootWithRandomWord(
address to,
Loot[] calldata loots,
uint256 randomWord
) external;
/**
* Validate that loots are properly formed. Reverts if the loots are not valid
*
* @param loots Loots to validate
* @return needsVRF Whether or not the loots specified require VRF to generate
*/
function validateLoots(Loot[] calldata loots)
external
view
returns (bool needsVRF);
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "../tokens/gameitems/GameItems.sol";
/** @title Game Items Mock for testing */
contract GameItemsMock is GameItems {
bytes4 public ITRAITSCONSUMER_INTERFACEID =
type(ITraitsConsumer).interfaceId;
constructor(address gameRegistryAddress) GameItems(gameRegistryAddress) {}
// Minting for test environemnts
function mintForTests(uint32 tokenId, uint256 amount) external {
_safeMint(_msgSender(), tokenId, amount);
}
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IRandomizerCallback} from "./IRandomizerCallback.sol";
uint256 constant ID = uint256(keccak256("game.piratenation.randomizer"));
interface IRandomizer is IERC165 {
/**
* Starts a VRF random number request
*
* @param callbackAddress Address to callback with the random numbers
* @param numWords Number of words to request from VRF
*
* @return requestId for the random number, will be passed to the callback contract
*/
function requestRandomWords(
IRandomizerCallback callbackAddress,
uint32 numWords
) external returns (uint256);
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IRandomizerCallback {
/**
* Callback for when the Chainlink request returns
*
* @param requestId Id of the random word request
* @param randomWords Random words that were generated by the VRF
*/
function fulfillRandomWordsCallback(
uint256 requestId,
uint256[] memory randomWords
) external;
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
interface IERC1155BeforeTokenTransferHandler {
/**
* Before transfer hook for GameItems. Performs any trait checks needed before transfer
*
* @param tokenContract Address of the token contract
* @param operator Operator address*
* @param from From address
* @param to To address
* @param ids Ids to transfer
* @param amounts Amounts to transfer
* @param data Additional data for transfer
*/
function beforeTokenTransfer(
address tokenContract,
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) external;
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
interface ITokenURIHandler {
/**
* Generates the TokenURI for a given token
*
* @param operator Sender requesting the tokenURI
* @param tokenContract TokenContract to get URI for
* @param tokenId Id of the token to get URI for
*
* @return TokenURI for the given token
*/
function tokenURI(
address operator,
address tokenContract,
uint256 tokenId
) external view returns (string memory);
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import {MANAGER_ROLE, MINTER_ROLE, GAME_LOGIC_CONTRACT_ROLE} from "../../Constants.sol";
import {IGameItems, ID} from "./IGameItems.sol";
import "../../TraitsConsumer.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import {IERC1155BeforeTokenTransferHandler} from "../IERC1155BeforeTokenTransferHandler.sol";
/** @title ERC1155 contract for Game Items */
contract GameItems is TraitsConsumer, IGameItems, ERC1155 {
/** TYPES **/
struct TypeInfo {
bool recyclable;
uint256 mints;
uint256 burns;
uint256 maxSupply;
}
/** MEMBERS **/
/// @notice Supply info for each type
mapping(uint256 => TypeInfo) private typeInfo;
/// @notice Current contract metadata URI for this contract
string private _contractURI;
/// @notice Handler for before token transfer events
address public beforeTokenTransferHandler;
/** EVENTS **/
/// @notice Emitted when contractURI has changed
event ContractURIUpdated(string uri);
/// @notice Everytime max supply is updated, this event is emitted. Can be used to track all items in the game
event TypeUpdated(uint256 indexed id, uint256 maxSupply, bool recyclable);
/** ERRORS **/
/// @notice maxSupply needs to be higher than minted
error MaxSupplyTooLow(uint256 needed, uint256 actual);
/// @notice Token type has not been defined
error InvalidTokenId();
/// @notice Amount to mint exceeds max supply
error NotEnoughSupply(uint256 needed, uint256 actual);
/** SETUP **/
constructor(address gameRegistryAddress)
ERC1155("")
TraitsConsumer(gameRegistryAddress, ID)
{
_defaultDescription = "Take to the seas with your pirate crew! Explore the world and gather XP, loot, and untold riches in a race to become the world's greatest pirate captain! Play at https://piratenation.game";
}
/** EXTERNAL **/
/**
* Sets the current contractURI for the contract
*
* @param _uri New contract URI
*/
function setContractURI(string calldata _uri) public onlyOwner {
_contractURI = _uri;
emit ContractURIUpdated(_uri);
}
/**
* @return Contract metadata URI for the NFT contract, used by NFT marketplaces to display collection inf
*/
function contractURI() public view returns (string memory) {
return _contractURI;
}
/**
* Sets a mintable token type up
*
* @param id Id of the token type to setup
* @param maxSupply Max Supply of the stoken
* @param recyclable Whether or not burns put tokens back into the pool to be minted again
*/
function setType(
uint256 id,
uint256 maxSupply,
bool recyclable
) external onlyRole(MANAGER_ROLE) {
uint256 mints = typeInfo[id].mints;
if (mints > maxSupply) {
revert MaxSupplyTooLow(mints, maxSupply);
}
typeInfo[id].maxSupply = maxSupply;
typeInfo[id].recyclable = recyclable;
emit TypeUpdated(id, maxSupply, recyclable);
}
/**
* Mints a ERC1155 token
*
* @param to Recipient of the token
* @param id Id of token to mint
* @param amount Quantity of token to mint
*/
function mint(
address to,
uint256 id,
uint256 amount
) external override onlyRole(MINTER_ROLE) whenNotPaused {
_safeMint(to, id, amount);
}
/**
* Burn a token - any payment / game logic should be handled in the game contract.
*
* @param from Account to burn from
* @param id Id of the token to burn
* @param amount Quantity to burn
*/
function burn(
address from,
uint256 id,
uint256 amount
) external override onlyRole(GAME_LOGIC_CONTRACT_ROLE) whenNotPaused {
typeInfo[id].burns += amount;
_burn(from, id, amount);
}
/**
* @param id Id of the token type to get supply info for
*
* @return Returns the current supply information for the given type
*/
function getInfoForType(uint256 id)
external
view
returns (TypeInfo memory)
{
if (typeInfo[id].maxSupply == 0) {
revert InvalidTokenId();
}
return typeInfo[id];
}
/** @return Token metadata URI for the given Id */
function uri(uint256 id) public view override returns (string memory) {
return _tokenURI(id);
}
/**
* @param id Id of the type to get data for
*
* @return How many of the given token id have been minted
*/
function minted(uint256 id)
external
view
virtual
override(IGameItems)
returns (uint256)
{
return typeInfo[id].mints;
}
/**
* Sets the before token transfer handler
*
* @param handlerAddress Address to the transfer hook handler contract
*/
function setBeforeTokenTransferHandler(address handlerAddress)
external
onlyOwner
{
beforeTokenTransferHandler = handlerAddress;
}
/**
* @inheritdoc IERC165
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(IERC165, TraitsConsumer, ERC1155)
returns (bool)
{
return
ERC165.supportsInterface(interfaceId) ||
TraitsConsumer.supportsInterface(interfaceId) ||
ERC1155.supportsInterface(interfaceId);
}
/*** INTERNAL ***/
// Executes the mint with appropriate checks and locking
function _safeMint(
address to,
uint256 id,
uint256 amount
) internal {
TypeInfo storage typeData = typeInfo[id];
if (typeData.recyclable) {
uint256 needed = typeData.mints - typeData.burns + amount;
if (needed > typeData.maxSupply) {
revert NotEnoughSupply(needed, typeData.maxSupply);
}
} else {
uint256 needed = typeData.mints + amount;
if (needed > typeData.maxSupply) {
revert NotEnoughSupply(needed, typeData.maxSupply);
}
}
typeData.mints += amount;
_mint(to, id, amount, "");
}
/**
* @notice Additional checks to prevent transfer of soulbound items, locked tokems, etc.
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual override {
if (beforeTokenTransferHandler != address(0)) {
IERC1155BeforeTokenTransferHandler handlerRef = IERC1155BeforeTokenTransferHandler(
beforeTokenTransferHandler
);
handlerRef.beforeTokenTransfer(
address(this),
operator,
from,
to,
ids,
amounts,
data
);
}
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
/**
* Message sender override to get Context to work with meta transactions
*
*/
function _msgSender()
internal
view
override(Context, GameRegistryConsumer)
returns (address)
{
return GameRegistryConsumer._msgSender();
}
/**
* Message data override to get Context to work with meta transactions
*
*/
function _msgData()
internal
view
override(Context, GameRegistryConsumer)
returns (bytes memory)
{
return GameRegistryConsumer._msgData();
}
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
uint256 constant ID = uint256(keccak256("game.piratenation.gameitems"));
interface IGameItems is IERC1155 {
/**
* Mints a ERC1155 token
*
* @param to Recipient of the token
* @param id Id of token to mint
* @param amount Quantity of token to mint
*/
function mint(
address to,
uint256 id,
uint256 amount
) external;
/**
* Burn a token - any payment / game logic should be handled in the game contract.
*
* @param from Account to burn from
* @param id Id of the token to burn
* @param amount Quantity to burn
*/
function burn(
address from,
uint256 id,
uint256 amount
) external;
/**
* @param id Id of the type to get data for
*
* @return How many of the given token id have been minted
*/
function minted(uint256 id) external view returns (uint256);
}