ERC-721
Overview
Max Total Supply
30 DEKOH
Holders
30
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 DEKOHLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
This contract contains unverified libraries: __CACHE_BREAKER__
Contract Name:
DekohDiamond
Compiler Version
v0.8.20+commit.a1b79de6
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IDiamondCut } from "hardhat-deploy/solc_0.8/diamond/interfaces/IDiamondCut.sol"; import { Diamond } from "hardhat-deploy/solc_0.8/diamond/Diamond.sol"; contract DekohDiamond is Diamond { /// @notice This construct a diamond contract /// @param _contractOwner the owner of the contract. With default DiamondCutFacet, this is the sole address allowed to make further cuts. /// @param _diamondCut the list of facet to add /// @param _initializations the list of initialization pair to execute. This allow to setup a contract with multiple level of independent initialization. constructor( address _contractOwner, IDiamondCut.FacetCut[] memory _diamondCut, Initialization[] memory _initializations ) payable Diamond(_contractOwner, _diamondCut, _initializations) { } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267Upgradeable { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/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.8.0/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/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSAUpgradeable.sol"; import "../../interfaces/IERC5267Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:storage-size 52 */ abstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable { bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @custom:oz-renamed-from _HASHED_NAME bytes32 private _hashedName; /// @custom:oz-renamed-from _HASHED_VERSION bytes32 private _hashedVersion; string private _name; string private _version; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { _name = name; _version = version; // Reset prior values in storage if upgrading _hashedName = 0; _hashedVersion = 0; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal virtual view returns (string memory) { return _name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal virtual view returns (string memory) { return _version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = _hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = _hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[48] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { 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) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 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 256, 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 << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMathUpgradeable { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { 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 = MathUpgradeable.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 `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// 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.9.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) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 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 256, 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 << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.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 `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { EnumerableSet } from '../../data/EnumerableSet.sol'; library AccessControlStorage { struct RoleData { EnumerableSet.AddressSet members; bytes32 adminRole; } struct Layout { mapping(bytes32 => RoleData) roles; } bytes32 internal constant DEFAULT_ADMIN_ROLE = 0x00; bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.AccessControl'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IAccessControlInternal } from './IAccessControlInternal.sol'; /** * @title AccessControl interface */ interface IAccessControl is IAccessControlInternal { /* * @notice query whether role is assigned to account * @param role role to query * @param account account to query * @return whether role is assigned to account */ function hasRole( bytes32 role, address account ) external view returns (bool); /* * @notice query admin role for given role * @param role role to query * @return admin role */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /* * @notice assign role to given account * @param role role to assign * @param account recipient of role assignment */ function grantRole(bytes32 role, address account) external; /* * @notice unassign role from given account * @param role role to unassign * @parm account */ function revokeRole(bytes32 role, address account) external; /** * @notice relinquish role * @param role role to relinquish */ function renounceRole(bytes32 role) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Partial AccessControl interface needed by internal functions */ interface IAccessControlInternal { event RoleAdminChanged( bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole ); event RoleGranted( bytes32 indexed role, address indexed account, address indexed sender ); event RoleRevoked( bytes32 indexed role, address indexed account, address indexed sender ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title Set implementation with enumeration functions * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license) */ library EnumerableSet { error EnumerableSet__IndexOutOfBounds(); struct Set { bytes32[] _values; // 1-indexed to allow 0 to signify nonexistence mapping(bytes32 => uint256) _indexes; } struct Bytes32Set { Set _inner; } struct AddressSet { Set _inner; } struct UintSet { Set _inner; } function at( Bytes32Set storage set, uint256 index ) internal view returns (bytes32) { return _at(set._inner, index); } function at( AddressSet storage set, uint256 index ) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } function at( UintSet storage set, uint256 index ) internal view returns (uint256) { return uint256(_at(set._inner, index)); } function contains( Bytes32Set storage set, bytes32 value ) internal view returns (bool) { return _contains(set._inner, value); } function contains( AddressSet storage set, address value ) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } function contains( UintSet storage set, uint256 value ) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } function indexOf( Bytes32Set storage set, bytes32 value ) internal view returns (uint256) { return _indexOf(set._inner, value); } function indexOf( AddressSet storage set, address value ) internal view returns (uint256) { return _indexOf(set._inner, bytes32(uint256(uint160(value)))); } function indexOf( UintSet storage set, uint256 value ) internal view returns (uint256) { return _indexOf(set._inner, bytes32(value)); } function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } function add( Bytes32Set storage set, bytes32 value ) internal returns (bool) { return _add(set._inner, value); } function add( AddressSet storage set, address value ) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } function remove( Bytes32Set storage set, bytes32 value ) internal returns (bool) { return _remove(set._inner, value); } function remove( AddressSet storage set, address value ) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } function remove( UintSet storage set, uint256 value ) internal returns (bool) { return _remove(set._inner, bytes32(value)); } function toArray( Bytes32Set storage set ) internal view returns (bytes32[] memory) { return set._inner._values; } function toArray( AddressSet storage set ) internal view returns (address[] memory) { bytes32[] storage values = set._inner._values; address[] storage array; assembly { array.slot := values.slot } return array; } function toArray( UintSet storage set ) internal view returns (uint256[] memory) { bytes32[] storage values = set._inner._values; uint256[] storage array; assembly { array.slot := values.slot } return array; } function _at( Set storage set, uint256 index ) private view returns (bytes32) { if (index >= set._values.length) revert EnumerableSet__IndexOutOfBounds(); return set._values[index]; } function _contains( Set storage set, bytes32 value ) private view returns (bool) { return set._indexes[value] != 0; } function _indexOf( Set storage set, bytes32 value ) private view returns (uint256) { unchecked { return set._indexes[value] - 1; } } function _length(Set storage set) private view returns (uint256) { return set._values.length; } function _add( Set storage set, bytes32 value ) private returns (bool status) { if (!_contains(set, value)) { set._values.push(value); set._indexes[value] = set._values.length; status = true; } } function _remove( Set storage set, bytes32 value ) private returns (bool status) { uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { unchecked { bytes32 last = set._values[set._values.length - 1]; // move last value to now-vacant index set._values[valueIndex - 1] = last; set._indexes[last] = valueIndex; } // clear last index set._values.pop(); delete set._indexes[value]; status = true; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IERC20Internal } from './IERC20Internal.sol'; /** * @title ERC20 interface * @dev see https://eips.ethereum.org/EIPS/eip-20 */ interface IERC20 is IERC20Internal { /** * @notice query the total minted token supply * @return token supply */ function totalSupply() external view returns (uint256); /** * @notice query the token balance of given account * @param account address to query * @return token balance */ function balanceOf(address account) external view returns (uint256); /** * @notice query the allowance granted from given holder to given spender * @param holder approver of allowance * @param spender recipient of allowance * @return token allowance */ function allowance( address holder, address spender ) external view returns (uint256); /** * @notice grant approval to spender to spend tokens * @dev prefer ERC20Extended functions to avoid transaction-ordering vulnerability (see https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729) * @param spender recipient of allowance * @param amount quantity of tokens approved for spending * @return success status (always true; otherwise function should revert) */ function approve(address spender, uint256 amount) external returns (bool); /** * @notice transfer tokens to given recipient * @param recipient beneficiary of token transfer * @param amount quantity of tokens to transfer * @return success status (always true; otherwise function should revert) */ function transfer( address recipient, uint256 amount ) external returns (bool); /** * @notice transfer tokens to given recipient on behalf of given holder * @param holder holder of tokens prior to transfer * @param recipient beneficiary of token transfer * @param amount quantity of tokens to transfer * @return success status (always true; otherwise function should revert) */ function transferFrom( address holder, address recipient, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title Partial ERC20 interface needed by internal functions */ interface IERC20Internal { event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title ERC2981 interface */ interface IERC2981Internal { }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; interface IPausableInternal { error Pausable__Paused(); error Pausable__NotPaused(); event Paused(address account); event Unpaused(address account); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IPausableInternal } from './IPausableInternal.sol'; import { PausableStorage } from './PausableStorage.sol'; /** * @title Internal functions for Pausable security control module. */ abstract contract PausableInternal is IPausableInternal { modifier whenNotPaused() { if (_paused()) revert Pausable__Paused(); _; } modifier whenPaused() { if (!_paused()) revert Pausable__NotPaused(); _; } /** * @notice query whether contract is paused * @return status whether contract is paused */ function _paused() internal view virtual returns (bool status) { status = PausableStorage.layout().paused; } /** * @notice Triggers paused state, when contract is unpaused. */ function _pause() internal virtual whenNotPaused { PausableStorage.layout().paused = true; emit Paused(msg.sender); } /** * @notice Triggers unpaused state, when contract is paused. */ function _unpause() internal virtual whenPaused { delete PausableStorage.layout().paused; emit Unpaused(msg.sender); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; library PausableStorage { struct Layout { bool paused; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.Pausable'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { ERC2981Storage } from './ERC2981Storage.sol'; import { IERC2981Internal } from '../../../interfaces/IERC2981Internal.sol'; /** * @title ERC2981 internal functions */ abstract contract ERC2981Internal is IERC2981Internal { /** * @notice calculate how much royalty is owed and to whom * @dev royalty must be paid in addition to, rather than deducted from, salePrice * @param tokenId the ERC721 or ERC1155 token id to query for royalty information * @param salePrice the sale price of the given asset * @return royaltyReceiver rightful recipient of royalty * @return royalty amount of royalty owed */ function _royaltyInfo( uint256 tokenId, uint256 salePrice ) internal view virtual returns (address royaltyReceiver, uint256 royalty) { uint256 royaltyBPS = _getRoyaltyBPS(tokenId); // intermediate multiplication overflow is theoretically possible here, but // not an issue in practice because of practical constraints of salePrice return (_getRoyaltyReceiver(tokenId), (royaltyBPS * salePrice) / 10000); } /** * @notice query the royalty rate (denominated in basis points) for given token id * @dev implementation supports per-token-id values as well as a global default * @param tokenId token whose royalty rate to query * @return royaltyBPS royalty rate */ function _getRoyaltyBPS( uint256 tokenId ) internal view virtual returns (uint16 royaltyBPS) { ERC2981Storage.Layout storage l = ERC2981Storage.layout(); royaltyBPS = l.royaltiesBPS[tokenId]; if (royaltyBPS == 0) { royaltyBPS = l.defaultRoyaltyBPS; } } /** * @notice query the royalty receiver for given token id * @dev implementation supports per-token-id values as well as a global default * @param tokenId token whose royalty receiver to query * @return royaltyReceiver royalty receiver */ function _getRoyaltyReceiver( uint256 tokenId ) internal view virtual returns (address royaltyReceiver) { ERC2981Storage.Layout storage l = ERC2981Storage.layout(); royaltyReceiver = l.royaltyReceivers[tokenId]; if (royaltyReceiver == address(0)) { royaltyReceiver = l.defaultRoyaltyReceiver; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; library ERC2981Storage { struct Layout { // token id -> royalty (denominated in basis points) mapping(uint256 => uint16) royaltiesBPS; uint16 defaultRoyaltyBPS; // token id -> receiver address mapping(uint256 => address) royaltyReceivers; address defaultRoyaltyReceiver; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.ERC2981'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { UintUtils } from './UintUtils.sol'; library AddressUtils { using UintUtils for uint256; error AddressUtils__InsufficientBalance(); error AddressUtils__NotContract(); error AddressUtils__SendValueFailed(); function toString(address account) internal pure returns (string memory) { return uint256(uint160(account)).toHexString(20); } function isContract(address account) internal view returns (bool) { uint256 size; assembly { size := extcodesize(account) } return size > 0; } function sendValue(address payable account, uint256 amount) internal { (bool success, ) = account.call{ value: amount }(''); if (!success) revert AddressUtils__SendValueFailed(); } function functionCall( address target, bytes memory data ) internal returns (bytes memory) { return functionCall(target, data, 'AddressUtils: failed low-level call'); } function functionCall( address target, bytes memory data, string memory error ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, error); } function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, 'AddressUtils: failed low-level call with value' ); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) internal returns (bytes memory) { if (value > address(this).balance) revert AddressUtils__InsufficientBalance(); return _functionCallWithValue(target, data, value, error); } /** * @notice execute arbitrary external call with limited gas usage and amount of copied return data * @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License) * @param target recipient of call * @param gasAmount gas allowance for call * @param value native token value to include in call * @param maxCopy maximum number of bytes to copy from return data * @param data encoded call data * @return success whether call is successful * @return returnData copied return data */ function excessivelySafeCall( address target, uint256 gasAmount, uint256 value, uint16 maxCopy, bytes memory data ) internal returns (bool success, bytes memory returnData) { returnData = new bytes(maxCopy); assembly { // execute external call via assembly to avoid automatic copying of return data success := call( gasAmount, target, value, add(data, 0x20), mload(data), 0, 0 ) // determine whether to limit amount of data to copy let toCopy := returndatasize() if gt(toCopy, maxCopy) { toCopy := maxCopy } // store the length of the copied bytes mstore(returnData, toCopy) // copy the bytes from returndata[0:toCopy] returndatacopy(add(returnData, 0x20), 0, toCopy) } } function _functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) private returns (bytes memory) { if (!isContract(target)) revert AddressUtils__NotContract(); (bool success, bytes memory returnData) = target.call{ value: value }( data ); if (success) { return returnData; } else if (returnData.length > 0) { assembly { let returnData_size := mload(returnData) revert(add(32, returnData), returnData_size) } } else { revert(error); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IERC20 } from '../interfaces/IERC20.sol'; import { AddressUtils } from './AddressUtils.sol'; /** * @title Safe ERC20 interaction library * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license) */ library SafeERC20 { using AddressUtils for address; error SafeERC20__ApproveFromNonZeroToNonZero(); error SafeERC20__DecreaseAllowanceBelowZero(); error SafeERC20__OperationFailed(); function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transfer.selector, to, value) ); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value) ); } /** * @dev safeApprove (like approve) should only be called when setting an initial allowance or when resetting it to zero; otherwise prefer safeIncreaseAllowance and safeDecreaseAllowance */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { if ((value != 0) && (token.allowance(address(this), spender) != 0)) revert SafeERC20__ApproveFromNonZeroToNonZero(); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, value) ); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); if (oldAllowance < value) revert SafeERC20__DecreaseAllowanceBelowZero(); uint256 newAllowance = oldAllowance - value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } } /** * @notice send transaction data and check validity of return value, if present * @param token ERC20 token interface * @param data transaction data */ function _callOptionalReturn(IERC20 token, bytes memory data) private { bytes memory returndata = address(token).functionCall( data, 'SafeERC20: low-level call failed' ); if (returndata.length > 0) { if (!abi.decode(returndata, (bool))) revert SafeERC20__OperationFailed(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title utility functions for uint256 operations * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license) */ library UintUtils { error UintUtils__InsufficientHexLength(); bytes16 private constant HEX_SYMBOLS = '0123456789abcdef'; function add(uint256 a, int256 b) internal pure returns (uint256) { return b < 0 ? sub(a, -b) : a + uint256(b); } function sub(uint256 a, int256 b) internal pure returns (uint256) { return b < 0 ? add(a, -b) : a - uint256(b); } function toString(uint256 value) internal pure returns (string memory) { if (value == 0) { return '0'; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return '0x00'; } uint256 length = 0; for (uint256 temp = value; temp != 0; temp >>= 8) { unchecked { length++; } } return toHexString(value, 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'; unchecked { for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_SYMBOLS[value & 0xf]; value >>= 4; } } if (value != 0) revert UintUtils__InsufficientHexLength(); return string(buffer); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title DekohDiamondStorage /// @author Martin Wawrusch for Roji Inc. /// @notice Storage for the diamond. This storage should only be used for /// admin level data like intialization status. /// Put all other data into facets and their storage. library DekohDiamondStorage { struct Layout { /// @dev Set to true when version 1 has been initialized. bool initializedV1; } bytes32 internal constant STORAGE_SLOT = keccak256('io.rojistudios.dekoh.storage.DekohDiamondStorage'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import {LibDiamond} from "hardhat-deploy/solc_0.8/diamond/libraries/LibDiamond.sol"; import {UsingDiamondOwner} from "hardhat-deploy/solc_0.8/diamond/UsingDiamondOwner.sol"; import { IDekohInitV1Facet } from './IDekohInitV1Facet.sol'; import { RolesLib } from '../../../facets/RolesLib.sol'; import { AccessControlLib } from '../../../facets/AccessControl/AccessControlLib.sol'; import { MetadataNameSymbolUpdateLibERC721A } from '../../../facets/MetadataNameSymbolUpdate/MetadataNameSymbolUpdateLibERC721A.sol'; import { BasicTokenURIStorage } from '../../../facets/BasicTokenURI/BasicTokenURIStorage.sol'; import { FakeERC173Storage } from '../../../facets/FakeERC173/FakeERC173Storage.sol'; import { ERC712Lib } from '../../../facets/ERC712/ERC712Lib.sol'; import { RoyaltiesERC2981Lib } from '../../../facets/RoyaltiesERC2981/RoyaltiesERC2981Lib.sol'; import { OperatorFiltererLib } from '../../../facets/OperatorFilterer/OperatorFiltererLib.sol'; import { ROJIInterfacesLib } from '../../../interfaces/ROJIInterfacesLib.sol'; import { DekohDiamondStorage } from '../../DekohDiamondStorage.sol'; import { OpenSeaContractStorage } from "../../../facets/OpenSeaContract/OpenSeaContractStorage.sol"; import { ERC721AStorage } from "../../../facets/ERC721A/ERC721AStorage.sol"; /// @title DekohInitV1Facet /// @author Martin Wawrusch for Roji Inc. /// @notice Initializer facet to be used on the verse diamond. contract DekohInitV1Facet is UsingDiamondOwner, IDekohInitV1Facet { address constant ANIMEMEELABS = 0x328424E95EC34CC062627508efE55ad01988adAb; /// @inheritdoc IDekohInitV1Facet function dekohInitV1( address adminUser, address diamondOwner ) external /* onlyOwner */ { if(DekohDiamondStorage.layout().initializedV1) { revert AlreadyInitialized(); } DekohDiamondStorage.layout().initializedV1 = true; // all the interfaces LibDiamond.diamondStorage().supportedInterfaces[ROJIInterfacesLib.INTERFACE_ID_ERC721] = true; LibDiamond.diamondStorage().supportedInterfaces[ROJIInterfacesLib.INTERFACE_ID_ERC721_METADATA] = true; LibDiamond.diamondStorage().supportedInterfaces[ROJIInterfacesLib.INTERFACE_ID_ERC4494] = true; LibDiamond.diamondStorage().supportedInterfaces[ROJIInterfacesLib.INTERFACE_ID_ERC2981] = true; LibDiamond.diamondStorage().supportedInterfaces[ROJIInterfacesLib.INTERFACE_ID_ROJI_VERSIONED_CONTRACT] = true; LibDiamond.diamondStorage().supportedInterfaces[ROJIInterfacesLib.INTERFACE_ID_IERC4906] = true; AccessControlLib.grantRole(RolesLib.ROLE_ACCESS_CONTROL_ADMIN, adminUser); AccessControlLib.grantRole(RolesLib.ROLE_FINANCE, adminUser); AccessControlLib.grantRole(RolesLib.ROLE_OPERATIONS, adminUser); AccessControlLib.grantRole(RolesLib.ROLE_METADATA_UPDATE, adminUser); AccessControlLib.grantRole(RolesLib.ROLE_ADMIN_MINTING, adminUser); AccessControlLib.grantRole(RolesLib.ROLE_ADMIN_BURNING, adminUser); BasicTokenURIStorage.layout().baseTokenURI = "https://static.rojiapi.com/meta-animemelabs-dekoh/tokens/"; ERC712Lib.init("Animeme Labs", "1"); ERC721AStorage.layout()._currentIndex = 1; // This works together with _startTokenId being hardcoded to 1 FakeERC173Storage.layout().owner = ANIMEMEELABS; MetadataNameSymbolUpdateLibERC721A._updateNameAndSymbol("Dekoh", "DEKOH"); OpenSeaContractStorage.layout().contractURI = "https://static.rojiapi.com/meta-animemelabs-dekoh/contract.json"; OperatorFiltererLib._init(); RoyaltiesERC2981Lib._setDefaultRoyalty(ANIMEMEELABS, 750); // Make this the last one, just for giggles LibDiamond.diamondStorage().contractOwner = diamondOwner; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IDekohInitV1Facet /// @author Martin Wawrusch for Roji Inc. /// @notice Initializer facet to be used for the DekohDiamond contract. interface IDekohInitV1Facet { /// @dev Error thrown when `dekohInitV1` is called after initialization error AlreadyInitialized(); /// @dev Initializes the diamond contract. /// @param adminUser the admin user for the facets. /// @param diamondOwner the controller of the diamond, including upgrading facets. function dekohInitV1(address adminUser, address diamondOwner) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IAccessControlFacet } from "./IAccessControlFacet.sol"; import { EnumerableSet } from '@solidstate/contracts/data/EnumerableSet.sol'; import { AddressUtils } from '@solidstate/contracts/utils/AddressUtils.sol'; import { UintUtils } from '@solidstate/contracts/utils/UintUtils.sol'; import { IAccessControlInternal } from '@solidstate/contracts/access/access_control/IAccessControlInternal.sol'; import { AccessControlStorage } from '@solidstate/contracts/access/access_control/AccessControlStorage.sol'; import { UsingAccessControl } from './UsingAccessControl.sol'; import { AccessControlLib} from './AccessControlLib.sol'; import { IAccessControl } from "@solidstate/contracts/access/access_control/IAccessControl.sol"; /// @title AccessControlFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Implements the facet for access control. This version of access control is not tied to /// the ROJIVerse access control. contract AccessControlFacet is UsingAccessControl, IAccessControlFacet { /// @inheritdoc IAccessControl function grantRole( bytes32 role, address account ) external onlyAccessControlAdmin { AccessControlLib.grantRole(role, account); } /// @inheritdoc IAccessControl function hasRole( bytes32 role, address account ) external view returns (bool) { return AccessControlLib.hasRole(role, account); } /// @inheritdoc IAccessControl function getRoleAdmin(bytes32 role) external view returns (bytes32) { return AccessControlLib.getRoleAdmin(role); } /// @inheritdoc IAccessControl function revokeRole( bytes32 role, address account ) external onlyAccessControlAdmin { AccessControlLib.revokeRole(role, account); } /// @inheritdoc IAccessControl function renounceRole(bytes32 role) external { AccessControlLib.renounceRole(role); } /** * @notice Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember( bytes32 role, uint256 index ) external view returns (address) { return AccessControlLib.getRoleMember(role, index); } /** * @notice Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256) { return AccessControlLib.getRoleMemberCount(role); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { EnumerableSet } from '@solidstate/contracts/data/EnumerableSet.sol'; import { AddressUtils } from '@solidstate/contracts/utils/AddressUtils.sol'; import { UintUtils } from '@solidstate/contracts/utils/UintUtils.sol'; import { AccessControlStorage } from '@solidstate/contracts/access/access_control/AccessControlStorage.sol'; import {IAccessControlInternal } from "@solidstate/contracts/access/access_control/IAccessControlInternal.sol"; /// @title AccessControlLib /// @author Martin Wawrusch for Roji Inc. /// @notice Functionality for access control outside of ROJIVerse. library AccessControlLib { using AddressUtils for address; using EnumerableSet for EnumerableSet.AddressSet; using UintUtils for uint256; event RoleAdminChanged( bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole ); event RoleGranted( bytes32 indexed role, address indexed account, address indexed sender ); event RoleRevoked( bytes32 indexed role, address indexed account, address indexed sender ); // /// @dev The admin role for Access Control // /// 0x0000000000000000000000000000000000000000000000000000000000000000 // bytes32 internal constant ROLE_ACCESS_CONTROL_ADMIN = bytes32(0); /* * @notice query whether role is assigned to account * @param role role to query * @param account account to query * @return whether role is assigned to account */ function hasRole( bytes32 role, address account ) internal view returns (bool) { return AccessControlStorage.layout().roles[role].members.contains(account); } // /** // * @notice revert if sender does not have given role // * @param role role to query // */ // function checkRole(bytes32 role) internal view virtual { // checkRole(role, msg.sender); // } /** * @notice revert if given account does not have given role * @param role role to query * @param account to query */ function checkRole(bytes32 role, address account) internal view { if (!hasRole(role, account)) { revert( string( abi.encodePacked( 'AccessControl: account ', account.toString(), ' is missing role ', uint256(role).toHexString(32) ) ) ); } } /* * @notice query admin role for given role * @param role role to query * @return admin role */ function getRoleAdmin( bytes32 role ) internal view returns (bytes32) { return AccessControlStorage.layout().roles[role].adminRole; } /** * @notice set role as admin role * @param role role to set * @param adminRole admin role to set */ function setRoleAdmin(bytes32 role, bytes32 adminRole) internal { bytes32 previousAdminRole = getRoleAdmin(role); AccessControlStorage.layout().roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /* * @notice assign role to given account * @param role role to assign * @param account recipient of role assignment */ function grantRole(bytes32 role, address account) internal { AccessControlStorage.layout().roles[role].members.add(account); emit RoleGranted(role, account, msg.sender); } /* * @notice unassign role from given account * @param role role to unassign * @parm account */ function revokeRole(bytes32 role, address account) internal { AccessControlStorage.layout().roles[role].members.remove(account); emit RoleRevoked(role, account, msg.sender); } /** * @notice relinquish role * @param role role to relinquish */ function renounceRole(bytes32 role) internal { revokeRole(role, msg.sender); } /** * @notice query role for member at given index * @param role role to query * @param index index to query */ function getRoleMember( bytes32 role, uint256 index ) internal view returns (address) { return AccessControlStorage.layout().roles[role].members.at(index); } /** * @notice query role for member count * @param role role to query */ function getRoleMemberCount( bytes32 role ) internal view returns (uint256) { return AccessControlStorage.layout().roles[role].members.length(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import {IAccessControl } from "@solidstate/contracts/access/access_control/IAccessControl.sol"; /// @title Exposes a contractURI property that is used by opensea to retrieve collection metadata. /// @author Martin Wawrusch for Roji Inc. interface IAccessControlFacet is IAccessControl { }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { AccessControlLib } from './AccessControlLib.sol'; import { RolesLib } from '../RolesLib.sol'; interface IUsingAccessControl { /// @dev The caller is not authorized. error MissingRole(bytes32 role, address account); } /// @title UsingSecurity /// @author Martin Wawrusch for Roji Inc. /// @notice This contract provides modifiers for access control. Inherit from it and use the appropriate modifier. abstract contract UsingAccessControl is IUsingAccessControl { /// @dev Returns the sender. This can be overridden if necessary for meta transactions. /// @return The sender. Defaults to `msg.sender`. function _msgSenderROJI() internal view virtual returns (address) { return msg.sender; } /// @dev Ensures that the current sender is in the ROJIVerse `role`. /// @param role The role to check for. /// This checks against the ROJIVerse access control. The sender is retrieved through /// `_msgSenderROJI()`, which can be overridden in decendent contracts. modifier onlyAccessControlRole(bytes32 role) { AccessControlLib.checkRole(role, _msgSenderROJI()); _; } /// @dev Ensures that the current sender is in the `ROLE_ACCESS_CONTROL_ADMIN` role. /// This checks against the contracts access control control. The sender is retrieved through /// `_msgSenderROJI()`, which can be overridden in decendent contracts. modifier onlyAccessControlAdmin() { AccessControlLib.checkRole(RolesLib.ROLE_ACCESS_CONTROL_ADMIN, _msgSenderROJI()); _; } /// @dev Ensures that the current sender is in the `ROLE_FINANCE` role. /// This checks against the contracts access control control. The sender is retrieved through /// `_msgSenderROJI()`, which can be overridden in decendent contracts. modifier onlyAccessControlFinance() { AccessControlLib.checkRole(RolesLib.ROLE_FINANCE, _msgSenderROJI()); _; } /// @dev Ensures that the current sender is in the `ROLE_OPERATIONS` role. /// This checks against the contracts access control control. The sender is retrieved through /// `_msgSenderROJI()`, which can be overridden in decendent contracts. modifier onlyAccessControlOperations() { AccessControlLib.checkRole(RolesLib.ROLE_OPERATIONS, _msgSenderROJI()); _; } /// @dev Ensures that the current sender is in the `ROLE_METADATA_UPDATE` role. /// This checks against the contracts access control control. The sender is retrieved through /// `_msgSenderROJI()`, which can be overridden in decendent contracts. modifier onlyAccessControlMetadataUpdate() { AccessControlLib.checkRole(RolesLib.ROLE_METADATA_UPDATE, _msgSenderROJI()); _; } /// @dev Ensures that the current sender is in the `ROLE_ADMIN_MINTING` role. /// This checks against the contracts access control control. The sender is retrieved through /// `_msgSenderROJI()`, which can be overridden in decendent contracts. modifier onlyAccessControlAdminMinting() { AccessControlLib.checkRole(RolesLib.ROLE_ADMIN_MINTING, _msgSenderROJI()); _; } /// @dev Ensures that the current sender is in the `ROLE_ADMIN_BURNING` role. /// This checks against the contracts access control control. The sender is retrieved through /// `_msgSenderROJI()`, which can be overridden in decendent contracts. modifier onlyAccessControlAdminBurning() { AccessControlLib.checkRole(RolesLib.ROLE_ADMIN_BURNING, _msgSenderROJI()); _; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IAdminMinterERC721AFacet } from "./IAdminMinterERC721AFacet.sol"; import { UsingPausable } from '../Pausable/UsingPausable.sol'; import { UsingAccessControl } from '../AccessControl/UsingAccessControl.sol'; import {ERC721AUpgradeableInternal, ERC721AStorage} from '../../facets/ERC721A/ERC721AUpgradeableInternal.sol'; /// @title AdminMinterERC721AFacetAccessControl /// @author Martin Wawrusch for Roji Inc. /// @notice Minting facet implementation for 1155 NFTs for admins. contract AdminMinterERC721AFacetAccessControl is ERC721AUpgradeableInternal, UsingPausable, UsingAccessControl, IAdminMinterERC721AFacet { /// @inheritdoc IAdminMinterERC721AFacet function adminMint(address to, uint256 quanity ) external onlyAccessControlAdminMinting { _safeMint(to, quanity, ""); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IAdminMinterERC721AFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Facet that allows admins to mint 1155 NFTs. interface IAdminMinterERC721AFacet { /// @notice Mints an 1155 NFT with the specified quantity. /// @param to The address that should receive the NFT. If this is a contract, then the contract must be ERC1155 receiver conforming. /// @param quanity The quanity of the tokens to mint. function adminMint(address to, uint256 quanity ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IBasicTokenURIFacet } from "./IBasicTokenURIFacet.sol"; import { BasicTokenURIStorage } from "./BasicTokenURIStorage.sol"; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; import { ERC721AUpgradeableInternal } from "../ERC721A/ERC721AUpgradeableInternal.sol"; import { StringsUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import { MetadataUpdate4906Lib } from '../MetadataUpdate4906/MetadataUpdate4906Lib.sol'; /// @title BasicTokenURIStorage /// @author Martin Wawrusch for Roji Inc. /// @notice Implements the facet for a basic token URI storage implementation. See `setBaseTokenURI` for details. contract BasicTokenURIERC721AFacet is ERC721AUpgradeableInternal, UsingAccessControl, IBasicTokenURIFacet { using StringsUpgradeable for uint256; /// @inheritdoc IBasicTokenURIFacet function tokenURI(uint256 tokenId) public view returns (string memory) { if(!_exists(tokenId)) {revert URIQueryForNonexistentToken(); } return string(abi.encodePacked(BasicTokenURIStorage.layout().baseTokenURI, tokenId.toString(), ".json")); } /// @inheritdoc IBasicTokenURIFacet function baseTokenURI() public view returns (string memory) { return BasicTokenURIStorage.layout().baseTokenURI; } /// @inheritdoc IBasicTokenURIFacet function setBaseTokenURI(string calldata baseTokenURI_) external onlyAccessControlAdmin { BasicTokenURIStorage.layout().baseTokenURI = baseTokenURI_; if(_nextTokenId() > _startTokenId()) { MetadataUpdate4906Lib._notifyBatchMetadataUpdated(_startTokenId(), _nextTokenId() - 1); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; library BasicTokenURIStorage { struct Layout { string baseTokenURI; } bytes32 internal constant STORAGE_SLOT = keccak256('io.roji.facets.storage.BasicTokenURIStorage'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IBasicTokenURIFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Defines the facet for a basic token URI storage implementation. See `setBaseTokenURI` for details. interface IBasicTokenURIFacet { /// @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. /// Throws `URIQueryForNonexistentToken` if `tokenId` does not exist. /// @param tokenId uint256 ID of the token to query. /// @return string URI of given token. function tokenURI(uint256 tokenId) external view returns (string memory); /// @dev Returns the baseTokenURI which is used to construct the tokenURI. See `setBaseTokenURI` for details. /// @return string The baseTokenURI. function baseTokenURI() external view returns (string memory); /// @dev Sets the baseTokenURI. /// The {tokenURI}, by default, is composed of baseTokenURI + tokenId + .json. /// Requires `ROLE_ROJI_ADMIN` membership. /// @param baseTokenURI_ The new baseTokenURI, which must end with a forward slash. /// Example: https://myserver.com/metadata/ function setBaseTokenURI(string calldata baseTokenURI_) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IDiamondOwnerFacet } from "./IDiamondOwnerFacet.sol"; import { LibDiamond} from "hardhat-deploy/solc_0.8/diamond/libraries/LibDiamond.sol"; import { DiamondOwnerStorage } from "./DiamondOwnerStorage.sol"; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; /// @title DiamondOwnerStorage /// @author Martin Wawrusch for Roji Inc. /// @notice Implements the facet for a basic token URI storage implementation. See `setBaseTokenURI` for details. /// Requires the `DiamondOrProxyFacet` to be present. contract DiamondOwnerFacetAccessControl is UsingAccessControl, IDiamondOwnerFacet { /// @inheritdoc IDiamondOwnerFacet function diamondOwner() view external returns(address) { return LibDiamond.contractOwner(); } /// @inheritdoc IDiamondOwnerFacet function nomineeDiamondOwner() external view returns (address){ return DiamondOwnerStorage.layout().nomineeDiamondOwner; } /// @inheritdoc IDiamondOwnerFacet function acceptDiamondOwnership() external { if(DiamondOwnerStorage.layout().nomineeDiamondOwner == address(0x0)){ revert NomineeIsNotSet(); } if(DiamondOwnerStorage.layout().nomineeDiamondOwner != _msgSenderROJI()) { revert SenderIsNotNominee(_msgSenderROJI(), DiamondOwnerStorage.layout().nomineeDiamondOwner); } address previousOwner = LibDiamond.diamondStorage().contractOwner; LibDiamond.diamondStorage().contractOwner = DiamondOwnerStorage.layout().nomineeDiamondOwner; emit DiamondOwnershipTransferred(previousOwner, DiamondOwnerStorage.layout().nomineeDiamondOwner); } /// @inheritdoc IDiamondOwnerFacet /// @param account The proposed new owner of the diamond. Can be 0 address. function transferDiamondOwnership(address account) external { LibDiamond.enforceIsContractOwner(); DiamondOwnerStorage.layout().nomineeDiamondOwner = account; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; library DiamondOwnerStorage { struct Layout { /// The nominated new owner of the diamond. address nomineeDiamondOwner; } bytes32 internal constant STORAGE_SLOT = keccak256('io.roji.facets.storage.DiamondOwnerStorage'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IDiamondOwnerFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Defines the facet for a basic token URI storage implementation. See `setBaseTokenURI` for details. interface IDiamondOwnerFacet { /// @notice The sender is not the nominee, which is a requirement to accept a nomination. error SenderIsNotNominee(address sender, address nominee); /// @notice The nominee is not set, which is a requirement to accept a nomination. error NomineeIsNotSet(); /// @notice Emitted when ownership of the diamond changes /// @param previousOwner The previous owner of the diamond. /// @param newOwner The new owner of the diamond. event DiamondOwnershipTransferred(address indexed previousOwner, address indexed newOwner); /// @notice Get the address of the owner /// @return The address of the owner. function diamondOwner() view external returns(address); /// @notice Get the nominated owner who has permission to call acceptOwnership /// @return The address of the nominated owner. function nomineeDiamondOwner() external view returns (address); /// @notice Accept transfer of contract ownership function acceptDiamondOwnership() external; /// @notice Grants permission to `account` to accept the diamond ownership. /// This can only be called on the diamond, never on the proxy. /// Requires the caller to be the current owner. /// @param account The proposed new owner of the diamond. function transferDiamondOwnership(address account) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IERC712Facet } from "./IERC712Facet.sol"; import { ERC712Storage } from "./ERC712Storage.sol"; import { ERC712Storage } from './ERC712Storage.sol'; import { ERC712Lib } from './ERC712Lib.sol'; /// @title ERC712Facet /// @author Martin Wawrusch for Roji Inc. /// @notice Implements the EIP712 domain separator and eip712Domain (EIP-5267) methods. /// This provides the foundation for ERC-712 support. contract ERC712Facet is IERC712Facet { /// @inheritdoc IERC712Facet // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { return ERC712Lib._domainSeparatorV4(); } /// @inheritdoc IERC712Facet function eip712Domain() public view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require(ERC712Storage.layout()._hashedName == 0 && ERC712Storage.layout()._hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 ERC712Lib._EIP712Name(), ERC712Lib._EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { ECDSAUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; import { ERC712Storage } from './ERC712Storage.sol'; /// @title ERC712Lib /// @author Martin Wawrusch for Roji Inc. /// @notice Contains utility functions for the ERC712 implementation. library ERC712Lib { bytes32 internal constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @dev Initializes the storage with app name and version /// @param name The name of the app as used for the EIP712 domain separator. /// @param version The version of the app as used for the EIP712 domain separator. function init(string memory name, string memory version) internal { ERC712Storage.Layout storage l = ERC712Storage.layout(); // l._hashedName = keccak256(bytes(l._name)); // l._hashedVersion = keccak256(bytes(l._version)); l._name = name; l._version = version; // Reset prior values in storage if upgrading l._hashedName = 0; l._hashedVersion = 0; } /// @dev Returns the domain separator for the current chain. function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal view returns (string memory) { return ERC712Storage.layout()._name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal view returns (string memory) { return ERC712Storage.layout()._version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = ERC712Storage.layout()._hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = ERC712Storage.layout()._hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title ERC712Storage /// @author Martin Wawrusch for Roji Inc. /// @notice Storage for the ERC712 implementation. /// Based upon OpenZeppelin's ERC712 implementation. library ERC712Storage { struct Layout { bytes32 _hashedName; bytes32 _hashedVersion; string _name; string _version; } bytes32 internal constant STORAGE_SLOT = keccak256('io.roji.facets.storage.ERC712Storage'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IERC712Facet /// @author Martin Wawrusch for Roji Inc. /// @notice Exports the EIP712 domain separator and eip712Domain (EIP-5267) methods. /// This provides the foundation for ERC-712 support. interface IERC712Facet { /// @notice Returns the domain separator used in the encoding of the signature for permits, as defined by EIP-712 /// @return the bytes32 domain separator function DOMAIN_SEPARATOR() external view returns(bytes32); /// @dev See {EIP-5267}. function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; library ERC721AStorage { // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364). struct TokenApprovalRef { address value; } struct Layout { // ============================================================= // STORAGE // ============================================================= // The next token ID to be minted. uint256 _currentIndex; // The number of tokens burned. uint256 _burnCounter; // Token name string _name; // Token symbol string _symbol; // Mapping from token ID to ownership details // An empty struct value does not necessarily mean the token is unowned. // See {_packedOwnershipOf} implementation for details. // // Bits Layout: // - [0..159] `addr` // - [160..223] `startTimestamp` // - [224] `burned` // - [225] `nextInitialized` // - [232..255] `extraData` mapping(uint256 => uint256) _packedOwnerships; // Mapping owner address to address data. // // Bits Layout: // - [0..63] `balance` // - [64..127] `numberMinted` // - [128..191] `numberBurned` // - [192..255] `aux` mapping(address => uint256) _packedAddressData; // Mapping from token ID to approved address. mapping(uint256 => ERC721AStorage.TokenApprovalRef) _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) _operatorApprovals; } bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.ERC721A'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import {ERC721AUpgradeableInternal, ERC721AStorage} from './ERC721AUpgradeableInternal.sol'; import { Permit4494Lib } from '../Permit4494/Permit4494Lib.sol'; import { UsingOperatorFilterer } from '../OperatorFilterer/UsingOperatorFilterer.sol'; /** * @dev Interface of ERC721 token receiver. */ interface ERC721A__IERC721ReceiverUpgradeable { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } /** * @title ERC721A * * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721) * Non-Fungible Token Standard, including the Metadata extension. * Optimized for lower gas during batch mints. * * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...) * starting from `_startTokenId()`. * * Assumptions: * * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply. * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256). */ contract ERC721AUpgradeableFacet is ERC721AUpgradeableInternal, UsingOperatorFilterer { using ERC721AStorage for ERC721AStorage.Layout; /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() public view virtual returns (uint256) { // Counter underflow is impossible as _burnCounter cannot be incremented // more than `_currentIndex - _startTokenId()` times. unchecked { return ERC721AStorage.layout()._currentIndex - ERC721AStorage.layout()._burnCounter - _startTokenId(); } } // ============================================================= // ADDRESS DATA OPERATIONS // ============================================================= /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) public view virtual returns (uint256) { if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector); return ERC721AStorage.layout()._packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY; } // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() public view virtual returns (string memory) { return ERC721AStorage.layout()._name; } /** * @dev Returns the token collection symbol. */ function symbol() public view virtual returns (string memory) { return ERC721AStorage.layout()._symbol; } // ============================================================= // OWNERSHIPS OPERATIONS // ============================================================= /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) public view virtual returns (address) { return address(uint160(_packedOwnershipOf(tokenId))); } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}. * * Requirements: * * - The caller must own the token or be an approved operator. */ function approve(address to, uint256 tokenId) public payable onlyAllowedOperatorApproval(to) virtual { _approve(to, tokenId, true); } /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) public view virtual returns (address) { if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector); return ERC721AStorage.layout()._tokenApprovals[tokenId].value; } /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} * for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) public onlyAllowedOperatorApproval(operator) virtual { ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved; emit ApprovalForAll(_msgSenderERC721A(), operator, approved); } /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { return ERC721AStorage.layout()._operatorApprovals[owner][operator]; } // ============================================================= // TRANSFER OPERATIONS // ============================================================= /** * @dev Transfers `tokenId` from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) public payable virtual onlyAllowedOperator(from) { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS)); if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); _beforeTokenTransfers(from, to, tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // We can directly increment and decrement the balances. --ERC721AStorage.layout()._packedAddressData[from]; // Updates: `balance -= 1`. ++ERC721AStorage.layout()._packedAddressData[to]; // Updates: `balance += 1`. // Updates: // - `address` to the next owner. // - `startTimestamp` to the timestamp of transfering. // - `burned` to `false`. // - `nextInitialized` to `true`. ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData( to, _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != ERC721AStorage.layout()._currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. from, // `from`. toMasked, // `to`. tokenId // `tokenId`. ) } if (toMasked == 0) _revert(TransferToZeroAddress.selector); _afterTokenTransfers(from, to, tokenId, 1); } /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public payable virtual onlyAllowedOperator(from) { safeTransferFrom(from, to, tokenId, ''); } /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public payable virtual onlyAllowedOperator(from) { transferFrom(from, to, tokenId); if (to.code.length != 0) if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } } function _afterTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual override { Permit4494Lib._handleAfterTokenTransfers(startTokenId, quantity); super._afterTokenTransfers(from, to, startTokenId, quantity); } function _beforeTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual override { super._beforeTokenTransfers(from, to, startTokenId, quantity); } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import {ERC721AStorage} from './ERC721AStorage.sol'; import {IERC721AUpgradeable} from './IERC721AUpgradeable.sol'; interface ERC721A__IERC721ReceiverUpgradeable { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } /** * @title ERC721A * * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721) * Non-Fungible Token Standard, including the Metadata extension. * Optimized for lower gas during batch mints. * * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...) * starting from `_startTokenId()`. * * Assumptions: * * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply. * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256). */ contract ERC721AUpgradeableInternal is IERC721AUpgradeable { using ERC721AStorage for ERC721AStorage.Layout; // ============================================================= // CONSTANTS // ============================================================= // Mask of an entry in packed address data. uint256 internal constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; // The bit position of `numberMinted` in packed address data. uint256 internal constant _BITPOS_NUMBER_MINTED = 64; // The bit position of `numberBurned` in packed address data. uint256 internal constant _BITPOS_NUMBER_BURNED = 128; // The bit position of `aux` in packed address data. uint256 internal constant _BITPOS_AUX = 192; // Mask of all 256 bits in packed address data except the 64 bits for `aux`. uint256 internal constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; // The bit position of `startTimestamp` in packed ownership. uint256 internal constant _BITPOS_START_TIMESTAMP = 160; // The bit mask of the `burned` bit in packed ownership. uint256 internal constant _BITMASK_BURNED = 1 << 224; // The bit position of the `nextInitialized` bit in packed ownership. uint256 internal constant _BITPOS_NEXT_INITIALIZED = 225; // The bit mask of the `nextInitialized` bit in packed ownership. uint256 internal constant _BITMASK_NEXT_INITIALIZED = 1 << 225; // The bit position of `extraData` in packed ownership. uint256 internal constant _BITPOS_EXTRA_DATA = 232; // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. uint256 internal constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; // The mask of the lower 160 bits for addresses. uint256 internal constant _BITMASK_ADDRESS = (1 << 160) - 1; // The maximum `quantity` that can be minted with {_mintERC2309}. // This limit is to prevent overflows on the address data entries. // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309} // is required to cause an overflow, which is unrealistic. uint256 internal constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; // The `Transfer` event signature is given by: // `keccak256(bytes("Transfer(address,address,uint256)"))`. bytes32 internal constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; // ============================================================= // TOKEN COUNTING OPERATIONS // ============================================================= /** * @dev Returns the starting token ID. * To change the starting token ID, please override this function. */ function _startTokenId() internal view virtual returns (uint256) { return 1; // NOTE - CUSTOMIZED HERE } /** * @dev Returns the next token ID to be minted. */ function _nextTokenId() internal view virtual returns (uint256) { return ERC721AStorage.layout()._currentIndex; } /** * @dev Returns the total amount of tokens minted in the contract. */ function _totalMinted() internal view virtual returns (uint256) { // Counter underflow is impossible as `_currentIndex` does not decrement, // and it is initialized to `_startTokenId()`. unchecked { return ERC721AStorage.layout()._currentIndex - _startTokenId(); } } /** * @dev Returns the total number of tokens burned. */ function _totalBurned() internal view virtual returns (uint256) { return ERC721AStorage.layout()._burnCounter; } // ============================================================= // ADDRESS DATA OPERATIONS // ============================================================= /** * Returns the number of tokens minted by `owner`. */ function _numberMinted(address owner) internal view returns (uint256) { return (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the number of tokens burned by or on behalf of `owner`. */ function _numberBurned(address owner) internal view returns (uint256) { return (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). */ function _getAux(address owner) internal view returns (uint64) { return uint64(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_AUX); } /** * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). * If there are multiple variables, please pack them into a uint64. */ function _setAux(address owner, uint64 aux) internal virtual { uint256 packed = ERC721AStorage.layout()._packedAddressData[owner]; uint256 auxCasted; // Cast `aux` with assembly to avoid redundant masking. assembly { auxCasted := aux } packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX); ERC721AStorage.layout()._packedAddressData[owner] = packed; } // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, it can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ''; } // ============================================================= // OWNERSHIPS OPERATIONS // ============================================================= /** * @dev Gas spent here starts off proportional to the maximum mint batch size. * It gradually moves to O(1) as tokens get transferred around over time. */ function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnershipOf(tokenId)); } /** * @dev Returns the unpacked `TokenOwnership` struct at `index`. */ function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]); } /** * @dev Returns whether the ownership slot at `index` is initialized. * An uninitialized slot does not necessarily mean that the slot has no owner. */ function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) { return ERC721AStorage.layout()._packedOwnerships[index] != 0; } /** * @dev Initializes the ownership slot minted at `index` for efficiency purposes. */ function _initializeOwnershipAt(uint256 index) internal virtual { if (ERC721AStorage.layout()._packedOwnerships[index] == 0) { ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index); } } /** * Returns the packed ownership data of `tokenId`. */ function _packedOwnershipOf(uint256 tokenId) internal view returns (uint256 packed) { if (_startTokenId() <= tokenId) { packed = ERC721AStorage.layout()._packedOwnerships[tokenId]; // If the data at the starting slot does not exist, start the scan. if (packed == 0) { if (tokenId >= ERC721AStorage.layout()._currentIndex) _revert(OwnerQueryForNonexistentToken.selector); // Invariant: // There will always be an initialized ownership slot // (i.e. `ownership.addr != address(0) && ownership.burned == false`) // before an unintialized ownership slot // (i.e. `ownership.addr == address(0) && ownership.burned == false`) // Hence, `tokenId` will not underflow. // // We can directly compare the packed value. // If the address is zero, packed will be zero. for (;;) { unchecked { packed = ERC721AStorage.layout()._packedOwnerships[--tokenId]; } if (packed == 0) continue; if (packed & _BITMASK_BURNED == 0) return packed; // Otherwise, the token is burned, and we must revert. // This handles the case of batch burned tokens, where only the burned bit // of the starting slot is set, and remaining slots are left uninitialized. _revert(OwnerQueryForNonexistentToken.selector); } } // Otherwise, the data exists and we can skip the scan. // This is possible because we have already achieved the target condition. // This saves 2143 gas on transfers of initialized tokens. // If the token is not burned, return `packed`. Otherwise, revert. if (packed & _BITMASK_BURNED == 0) return packed; } _revert(OwnerQueryForNonexistentToken.selector); } /** * @dev Returns the unpacked `TokenOwnership` struct from `packed`. */ function _unpackedOwnership(uint256 packed) internal pure returns (TokenOwnership memory ownership) { ownership.addr = address(uint160(packed)); ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP); ownership.burned = packed & _BITMASK_BURNED != 0; ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA); } /** * @dev Packs ownership data into a single uint256. */ function _packOwnershipData(address owner, uint256 flags) internal view returns (uint256 result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`. result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags)) } } /** * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. */ function _nextInitializedFlag(uint256 quantity) internal pure returns (uint256 result) { // For branchless setting of the `nextInitialized` flag. assembly { // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`. result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) } } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted. See {_mint}. */ function _exists(uint256 tokenId) internal view virtual returns (bool result) { if (_startTokenId() <= tokenId) { if (tokenId < ERC721AStorage.layout()._currentIndex) { uint256 packed; while ((packed = ERC721AStorage.layout()._packedOwnerships[tokenId]) == 0) --tokenId; result = packed & _BITMASK_BURNED == 0; } } } /** * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`. */ function _isSenderApprovedOrOwner( address approvedAddress, address owner, address msgSender ) internal pure returns (bool result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. msgSender := and(msgSender, _BITMASK_ADDRESS) // `msgSender == owner || msgSender == approvedAddress`. result := or(eq(msgSender, owner), eq(msgSender, approvedAddress)) } } /** * @dev Returns the storage slot and value for the approved address of `tokenId`. */ function _getApprovedSlotAndAddress(uint256 tokenId) internal view returns (uint256 approvedAddressSlot, address approvedAddress) { ERC721AStorage.TokenApprovalRef storage tokenApproval = ERC721AStorage.layout()._tokenApprovals[tokenId]; // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`. assembly { approvedAddressSlot := tokenApproval.slot approvedAddress := sload(approvedAddressSlot) } } // ============================================================= // TRANSFER OPERATIONS // ============================================================= /** * @dev Hook that is called before a set of serially-ordered token IDs * are about to be transferred. This includes minting. * And also called before burning one token. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _beforeTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev Hook that is called after a set of serially-ordered token IDs * have been transferred. This includes minting. * And also called after one token has been burned. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been * transferred to `to`. * - When `from` is zero, `tokenId` has been minted for `to`. * - When `to` is zero, `tokenId` has been burned by `from`. * - `from` and `to` are never both zero. */ function _afterTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. * * `from` - Previous owner of the given token ID. * `to` - Target address that will receive the token. * `tokenId` - Token ID to be transferred. * `_data` - Optional data to send along with the call. * * Returns whether the call correctly returned the expected magic value. */ function _checkContractOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) internal returns (bool) { try ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (bytes4 retval) { return retval == ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { _revert(TransferToNonERC721ReceiverImplementer.selector); } assembly { revert(add(32, reason), mload(reason)) } } } // ============================================================= // MINT OPERATIONS // ============================================================= /** * @dev Mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {Transfer} event for each mint. */ function _mint(address to, uint256 quantity) internal virtual { uint256 startTokenId = ERC721AStorage.layout()._currentIndex; if (quantity == 0) _revert(MintZeroQuantity.selector); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are incredibly unrealistic. // `balance` and `numberMinted` have a maximum limit of 2**64. // `tokenId` has a maximum limit of 2**256. unchecked { // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; if (toMasked == 0) _revert(MintToZeroAddress.selector); uint256 end = startTokenId + quantity; uint256 tokenId = startTokenId; do { assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. 0, // `address(0)`. toMasked, // `to`. tokenId // `tokenId`. ) } // The `!=` check ensures that large values of `quantity` // that overflows uint256 will make the loop run out of gas. } while (++tokenId != end); ERC721AStorage.layout()._currentIndex = end; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Mints `quantity` tokens and transfers them to `to`. * * This function is intended for efficient minting only during contract creation. * * It emits only one {ConsecutiveTransfer} as defined in * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), * instead of a sequence of {Transfer} event(s). * * Calling this function outside of contract creation WILL make your contract * non-compliant with the ERC721 standard. * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 * {ConsecutiveTransfer} event is only permissible during contract creation. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {ConsecutiveTransfer} event. */ function _mintERC2309(address to, uint256 quantity) internal virtual { uint256 startTokenId = ERC721AStorage.layout()._currentIndex; if (to == address(0)) _revert(MintToZeroAddress.selector); if (quantity == 0) _revert(MintZeroQuantity.selector); if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are unrealistic due to the above check for `quantity` to be below the limit. unchecked { // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); ERC721AStorage.layout()._currentIndex = startTokenId + quantity; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Safely mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. * - `quantity` must be greater than 0. * * See {_mint}. * * Emits a {Transfer} event for each mint. */ function _safeMint( address to, uint256 quantity, bytes memory _data ) internal virtual { _mint(to, quantity); unchecked { if (to.code.length != 0) { uint256 end = ERC721AStorage.layout()._currentIndex; uint256 index = end - quantity; do { if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } } while (index < end); // Reentrancy protection. if (ERC721AStorage.layout()._currentIndex != end) _revert(bytes4(0)); } } } /** * @dev Equivalent to `_safeMint(to, quantity, '')`. */ function _safeMint(address to, uint256 quantity) internal virtual { _safeMint(to, quantity, ''); } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @dev Equivalent to `_approve(to, tokenId, false)`. */ function _approve(address to, uint256 tokenId) internal virtual { _approve(to, tokenId, false); } function _ownerOf(uint256 tokenId) internal view returns (address) { return address(uint160(_packedOwnershipOf(tokenId))); } /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the * zero address clears previous approvals. * * Requirements: * * - `tokenId` must exist. * * Emits an {Approval} event. */ function _approve( address to, uint256 tokenId, bool approvalCheck ) internal virtual { address owner = _ownerOf(tokenId); if (approvalCheck && _msgSenderERC721A() != owner) if (!_isApprovedForAll(owner, _msgSenderERC721A())) { _revert(ApprovalCallerNotOwnerNorApproved.selector); } ERC721AStorage.layout()._tokenApprovals[tokenId].value = to; emit Approval(owner, to, tokenId); } // ============================================================= // BURN OPERATIONS // ============================================================= /** * @dev Equivalent to `_burn(tokenId, false)`. */ function _burn(uint256 tokenId) internal virtual { _burn(tokenId, false); } function _isApprovedForAll(address owner, address operator) internal view returns (bool) { return ERC721AStorage.layout()._operatorApprovals[owner][operator]; } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId, bool approvalCheck) internal virtual { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); address from = address(uint160(prevOwnershipPacked)); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); if (approvalCheck) { // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!_isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); } _beforeTokenTransfers(from, address(0), tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // Updates: // - `balance -= 1`. // - `numberBurned += 1`. // // We can directly decrement the balance, and increment the number burned. // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`. ERC721AStorage.layout()._packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1; // Updates: // - `address` to the last owner. // - `startTimestamp` to the timestamp of burning. // - `burned` to `true`. // - `nextInitialized` to `true`. ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData( from, (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != ERC721AStorage.layout()._currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } emit Transfer(from, address(0), tokenId); _afterTokenTransfers(from, address(0), tokenId, 1); // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. unchecked { ERC721AStorage.layout()._burnCounter++; } } // ============================================================= // EXTRA DATA OPERATIONS // ============================================================= /** * @dev Directly sets the extra data for the ownership data `index`. */ function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual { uint256 packed = ERC721AStorage.layout()._packedOwnerships[index]; if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector); uint256 extraDataCasted; // Cast `extraData` with assembly to avoid redundant masking. assembly { extraDataCasted := extraData } packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA); ERC721AStorage.layout()._packedOwnerships[index] = packed; } /** * @dev Called during each token transfer to set the 24bit `extraData` field. * Intended to be overridden by the cosumer contract. * * `previousExtraData` - the value of `extraData` before transfer. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _extraData( address from, address to, uint24 previousExtraData ) internal view virtual returns (uint24) {} /** * @dev Returns the next extra data for the packed ownership data. * The returned result is shifted into position. */ function _nextExtraData( address from, address to, uint256 prevOwnershipPacked ) internal view returns (uint256) { uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA); return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA; } // ============================================================= // OTHER OPERATIONS // ============================================================= /** * @dev Returns the message sender (defaults to `msg.sender`). * * If you are writing GSN compatible contracts, you need to override this function. */ function _msgSenderERC721A() internal view virtual returns (address) { return msg.sender; } /** * @dev Converts a uint256 to its ASCII string decimal representation. */ function _toString(uint256 value) internal pure virtual returns (string memory str) { assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0. let m := add(mload(0x40), 0xa0) // Update the free memory pointer to allocate. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 0x20) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // prettier-ignore for { let temp := value } 1 {} { str := sub(str, 1) // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) // prettier-ignore if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /** * @dev For more efficient reverts. */ function _revert(bytes4 errorSelector) internal pure { assembly { mstore(0x00, errorSelector) revert(0x00, 0x04) } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /** * @dev Interface of ERC721A. */ interface IERC721AUpgradeable { /** * The caller must own the token or be an approved operator. */ error ApprovalCallerNotOwnerNorApproved(); /** * The token does not exist. */ error ApprovalQueryForNonexistentToken(); /** * Cannot query the balance for the zero address. */ error BalanceQueryForZeroAddress(); /** * Cannot mint to the zero address. */ error MintToZeroAddress(); /** * The quantity of tokens minted must be more than zero. */ error MintZeroQuantity(); /** * The token does not exist. */ error OwnerQueryForNonexistentToken(); /** * The caller must own the token or be an approved operator. */ error TransferCallerNotOwnerNorApproved(); /** * The token must be owned by `from`. */ error TransferFromIncorrectOwner(); /** * Cannot safely transfer to a contract that does not implement the * ERC721Receiver interface. */ error TransferToNonERC721ReceiverImplementer(); /** * Cannot transfer to the zero address. */ error TransferToZeroAddress(); /** * The token does not exist. */ error URIQueryForNonexistentToken(); /** * The `quantity` minted with ERC2309 exceeds the safety limit. */ error MintERC2309QuantityExceedsLimit(); /** * The `extraData` cannot be set on an unintialized ownership slot. */ error OwnershipNotInitializedForExtraData(); // ============================================================= // STRUCTS // ============================================================= struct TokenOwnership { // The address of the owner. address addr; // Stores the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. uint24 extraData; } /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables * (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IFakeERC173Facet } from "./IFakeERC173Facet.sol"; import { FakeERC173Storage } from "./FakeERC173Storage.sol"; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; /// @title FakeERC173FacetAccessControl /// @author Martin Wawrusch for Roji Inc. /// @notice Exposes an ERC173 ownership facet. The actual ownership is handled differently, this is only used for OpenSea and similar indexers contract FakeERC173FacetAccessControl is UsingAccessControl , IFakeERC173Facet { /// @inheritdoc IFakeERC173Facet function owner() view external returns(address) { return FakeERC173Storage.layout().owner; } /// @inheritdoc IFakeERC173Facet function transferOwnership(address _newOwner) external onlyAccessControlAdmin { address previousOwner = FakeERC173Storage.layout().owner; FakeERC173Storage.layout().owner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; library FakeERC173Storage { struct Layout { address owner; } bytes32 internal constant STORAGE_SLOT = keccak256('io.roji.facets.storage.FakeERC173Storage'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IFakeERC173Facet /// @author Martin Wawrusch for Roji Inc. /// @notice Exposes an ERC173 ownership facet. The actual ownership is handled differently, this is only used for OpenSea and similar indexers interface IFakeERC173Facet { /// @dev This emits when ownership of a contract changes. event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /// @notice Get the address of the owner /// @return The address of the owner. function owner() view external returns(address); /// @notice Set the address of the new owner of the contract /// @dev Set _newOwner to address(0) to renounce any ownership. /// @param _newOwner The address of the new owner of the contract function transferOwnership(address _newOwner) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IMetadataNameSymbolUpdateFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Allows updating the name and symbol of the contract. interface IMetadataNameSymbolUpdateFacet { /// Update the `name` and `symbol` of the NFT contract. /// When run in a proxy -> diamond scenario this is restricted to the proxy only and will revert on the diamond. /// @param name The new name of the contract. /// @param symbol The new symbol of the contract. It is recommended to keep the length at 11 characters or less, all caps. function updateNameAndSymbol(string memory name, string memory symbol) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IMetadataNameSymbolUpdateFacet } from "./IMetadataNameSymbolUpdateFacet.sol"; import { ERC721AStorage } from "../ERC721A/ERC721AStorage.sol"; import { MetadataNameSymbolUpdateLibERC721A } from "./MetadataNameSymbolUpdateLibERC721A.sol"; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; /// @title MetadataNameSymbolUpdateFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Allows updating the name and symbol of the contract. contract MetadataNameSymbolUpdateFacetERC721AAccessControl is UsingAccessControl, IMetadataNameSymbolUpdateFacet { /// @inheritdoc IMetadataNameSymbolUpdateFacet function updateNameAndSymbol(string memory name, string memory symbol) external onlyAccessControlAdmin { MetadataNameSymbolUpdateLibERC721A._updateNameAndSymbol(name, symbol); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { ERC721AStorage } from "../ERC721A/ERC721AStorage.sol"; library MetadataNameSymbolUpdateLibERC721A { /// Updates the name and symbol of the ERC721A. function _updateNameAndSymbol(string memory name, string memory symbol) internal { ERC721AStorage.layout()._name = name; ERC721AStorage.layout()._symbol = symbol; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; // import { IERC4906 } from "../../interfaces/IERC4906.sol"; /// @title Facet for notifying of metadata updates /// @author Martin Wawrusch for Roji Inc. interface IMetadataUpdate4906Facet /* is IERC4906 */ { /// @notice Notifies that the metadata for a token has been updated. /// /// @param tokenId The id of the token that was updated. function notifyMetadataUpdated(uint256 tokenId) external; /// @notice Notifies that the metadata for a range of tokens has been updated. /// /// @param fromTokenId The first id of the range of tokens that were updated. /// @param toTokenId The last id of the range of tokens that were updated. function notifyBatchMetadataUpdated(uint256 fromTokenId, uint256 toTokenId) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IMetadataUpdate4906Facet } from "./IMetadataUpdate4906Facet.sol"; import { MetadataUpdate4906Lib } from "./MetadataUpdate4906Lib.sol"; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; /// @title Implementation of a facet for notifying of metadata updates secured via AccessControl /// @author Martin Wawrusch for Roji Inc. contract MetadataUpdate4906FacetAccessControl is UsingAccessControl, IMetadataUpdate4906Facet { /// @inheritdoc IMetadataUpdate4906Facet function notifyMetadataUpdated(uint256 tokenId) external onlyAccessControlMetadataUpdate { MetadataUpdate4906Lib._notifyMetadataUpdated(tokenId); } /// @inheritdoc IMetadataUpdate4906Facet function notifyBatchMetadataUpdated(uint256 fromTokenId, uint256 toTokenId) external onlyAccessControlMetadataUpdate { MetadataUpdate4906Lib._notifyBatchMetadataUpdated(fromTokenId, toTokenId); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; library MetadataUpdate4906Lib { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId); /// @dev Notifies that the metadata for a token has been updated. /// /// @param tokenId The id of the token that was updated. function _notifyMetadataUpdated(uint256 tokenId) internal { emit MetadataUpdate(tokenId); } /// @dev Notifies that the metadata for a range of tokens has been updated. /// @param fromTokenId The first id of the range of tokens that were updated. /// @param toTokenId The last id of the range of tokens that were updated. function _notifyBatchMetadataUpdated(uint256 fromTokenId, uint256 toTokenId) internal { emit BatchMetadataUpdate(fromTokenId, toTokenId); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title Exposes a contractURI property that is used by opensea to retrieve collection metadata. /// @author Martin Wawrusch for Roji Inc. interface IOpenSeaContractFacet { /// @notice Emitted when the receiver has been updated for an NFT contract /// @param contractURI The new contract URI. This should point to some file, preferably stored on ipfs. event ContractURIUpdated( string contractURI); /// @notice Sets the contract URI that is used by opensea to retrieve contract info. /// /// @param contractURI_ The new contract URI. Can be null. function setContractURI(string calldata contractURI_) external; /// @notice Returns the contract URI as used by OpenSea. function contractURI() external view returns (string memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IOpenSeaContractFacet } from "./IOpenSeaContractFacet.sol"; import { OpenSeaContractStorage } from "./OpenSeaContractStorage.sol"; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; /// @title OpenSeaContractFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Exposes a contractURI property that is used by opensea to retrieve collection metadata. contract OpenSeaContractFacetAccessControl is UsingAccessControl, IOpenSeaContractFacet { /// @inheritdoc IOpenSeaContractFacet function setContractURI(string calldata contractURI_) external onlyAccessControlAdmin { OpenSeaContractStorage.layout().contractURI = contractURI_; emit ContractURIUpdated(contractURI_); } /// @inheritdoc IOpenSeaContractFacet function contractURI() public view returns (string memory) { return OpenSeaContractStorage.layout().contractURI; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; library OpenSeaContractStorage { struct Layout { /// The optional opensea metatdata URI string contractURI; } bytes32 internal constant STORAGE_SLOT = keccak256('io.roji.facets.storage.OpenSeaContractStorage'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; interface IOperatorFiltererFacet { /// @notice Emitted when an operator is not allowed. error OperatorNotAllowed(address operator); /// @notice Registers the contract with the registry. /// This must be called from the proxy. /// /// @param subscriptionOrRegistrantToCopy Provide a valid subscription address to copy the subscriptions from or the 0 address. /// @param subscribe registers and subscribes function registerOperatorFilterer(address subscriptionOrRegistrantToCopy, bool subscribe) external; /// @notice Unregisters the contract from the registry. function unregisterOperatorFilterer() external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IOperatorFiltererFacet } from "./IOperatorFiltererFacet.sol"; import { OperatorFiltererLib } from './OperatorFiltererLib.sol'; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; contract OperatorFiltererFacetAccessControl is UsingAccessControl, IOperatorFiltererFacet { /// @inheritdoc IOperatorFiltererFacet function registerOperatorFilterer(address subscriptionOrRegistrantToCopy, bool subscribe) external onlyAccessControlAdmin { OperatorFiltererLib._register(subscriptionOrRegistrantToCopy, subscribe); } /// @inheritdoc IOperatorFiltererFacet function unregisterOperatorFilterer() external onlyAccessControlAdmin { OperatorFiltererLib._unregister(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import {IOperatorFilterRegistry} from "operator-filter-registry/src/IOperatorFilterRegistry.sol"; import { IOperatorFiltererFacet } from './IOperatorFiltererFacet.sol'; /// @title OperatorFilterLib /// @author Martin Wawrusch for Roji Inc. /// @notice Contains functionality to implement operator filtering. library OperatorFiltererLib { IOperatorFilterRegistry constant OPERATOR_FILTER_REGISTRY = IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E); address constant CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS = 0x000000000000AAeB6D7670E522A718067333cd4E; address constant CANONICAL_CORI_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6; /** * @dev A helper function to check if the operator is allowed. */ function _checkFilterOperator(address operator) internal view { // Check registry code length to facilitate testing in environments without a deployed registry. if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) { // under normal circumstances, this function will revert rather than return false, but inheriting or // upgraded contracts may specify their own OperatorFilterRegistry implementations, which may behave // differently if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) { revert IOperatorFiltererFacet.OperatorNotAllowed(operator); } } } /// @dev Initializes with the default registry and subscribes. function _init() internal { _register(CANONICAL_CORI_SUBSCRIPTION, true); } /// @dev Registers the contract with the registry. /// This must be called from the proxy. /// /// @param subscriptionOrRegistrantToCopy Provide a valid subscription address to copy the subscriptions from or the 0 address. /// @param subscribe registers and subscribes function _register(address subscriptionOrRegistrantToCopy, bool subscribe) internal { // If an inheriting token contract is deployed to a network without the registry deployed, the modifier // will not revert, but the contract will need to be registered with the registry once it is deployed in // order for the modifier to filter addresses. if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) { if (!OPERATOR_FILTER_REGISTRY.isRegistered(address(this))) { if (subscribe) { OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy); } else { if (subscriptionOrRegistrantToCopy != address(0)) { OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy); } else { OPERATOR_FILTER_REGISTRY.register(address(this)); } } } } } /// @dev Unregisters the contract from the registry. function _unregister() internal { if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) { if (OPERATOR_FILTER_REGISTRY.isRegistered(address(this))) { OPERATOR_FILTER_REGISTRY.unregister(address(this)); } } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { OperatorFiltererLib } from './OperatorFiltererLib.sol'; /// @title Internal contract that exposed the pausable modifier /// @author Martin Wawrusch for Roji Inc. abstract contract UsingOperatorFilterer { /** * @dev A helper modifier to check if the operator is allowed. */ modifier onlyAllowedOperator(address from) virtual { // Allow spending tokens from addresses with balance // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred // from an EOA. if (from != msg.sender) { OperatorFiltererLib._checkFilterOperator(msg.sender); } _; } /** * @dev A helper modifier to check if the operator approval is allowed. */ modifier onlyAllowedOperatorApproval(address operator) virtual { OperatorFiltererLib._checkFilterOperator(operator); _; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IPausableFacet /// @author Martin Wawrusch for Roji Inc. /// @notice This facet defines the pausable functionality. interface IPausableFacet { /** * @notice query whether contract is paused * @return status whether contract is paused */ function paused() external view returns (bool status); /// @notice pauses the contract /// @dev requires that the contract is not paused function pause() external; /// @notice unpauses the contract /// @dev requires that the contract is paused function unpause() external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IPausableFacet } from "./IPausableFacet.sol"; import { PausableInternal } from '@solidstate/contracts/security/pausable/PausableInternal.sol'; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; /// @title PausableFacetAccessControl /// @author Martin Wawrusch for Roji Inc. /// @notice This facet implements the pausable functionality. /// This implementation of the facet requires access control (`AccessControlFacet`). contract PausableFacetAccessControl is PausableInternal, UsingAccessControl, IPausableFacet { /** * @inheritdoc IPausableFacet */ function paused() public view virtual returns (bool status) { status = _paused(); } /// @notice pauses the contract /// @dev requires that the contract is not paused function pause() external onlyAccessControlOperations { _pause(); } /// @notice unpauses the contract /// @dev requires that the contract is paused function unpause() external onlyAccessControlOperations { _unpause(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { PausableStorage } from '@solidstate/contracts/security/pausable/PausableStorage.sol'; import { IPausableInternal } from '@solidstate/contracts/security/pausable/IPausableInternal.sol'; /// @title Internal contract that exposed the pausable modifier /// @author Martin Wawrusch for Roji Inc. abstract contract UsingPausable is IPausableInternal { /// @dev Reverts when the contract is paused. modifier whenNotPaused() { if( PausableStorage.layout().paused ) { revert Pausable__Paused(); } _; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; interface IPermit4494Facet { /// ERC165 bytes to add to interface array - set in parent contract /// /// _INTERFACE_ID_ERC4494 = 0x5604e225 /// @notice Function to approve by way of owner signature /// @param spender the address to approve /// @param tokenId the index of the NFT to approve the spender on /// @param deadline a timestamp expiry for the permit /// @param signature a traditional or EIP-2098 signature function permit(address spender, uint256 tokenId, uint256 deadline, bytes memory signature) external; /// @notice Returns the nonce of an NFT - useful for creating permits /// @param tokenId the index of the NFT to get the nonce of /// @return the uint256 representation of the nonce function nonces(uint256 tokenId) external view returns(uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IPermit4494Facet } from "./IPermit4494Facet.sol"; import { Permit4494Storage } from "./Permit4494Storage.sol"; import { ERC721AUpgradeableInternal } from "../ERC721A/ERC721AUpgradeableInternal.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { CountersUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; import { EIP712Upgradeable } from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; import { ERC721AStorage } from "../ERC721A/ERC721AStorage.sol"; import { ERC712Lib } from '../ERC712/ERC712Lib.sol'; import { Permit4494Lib } from './Permit4494Lib.sol'; /// @title Permit4494ERC721AFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Requires the `ERC712Facet`. contract Permit4494ERC721AFacet is ERC721AUpgradeableInternal, IPermit4494Facet { using CountersUpgradeable for CountersUpgradeable.Counter; /// @inheritdoc IPermit4494Facet function nonces(uint256 tokenId_) external view returns(uint256) { return Permit4494Storage.layout().nonces[tokenId_].current(); } /// @inheritdoc IPermit4494Facet function permit( address spender, uint256 tokenId, uint256 deadline, bytes memory signature ) external { // solhint-disable-next-line not-rely-on-time require(block.timestamp <= deadline, "ERC721Permit: expired deadline"); bytes32 structHash = keccak256( abi.encode( Permit4494Lib.PERMIT_4494_TYPEHASH, spender, tokenId, Permit4494Storage.layout().nonces[tokenId].current(), deadline ) ); bytes32 hash = ERC712Lib._hashTypedDataV4(structHash); (address signer, ) = ECDSA.tryRecover(hash, signature); bool isValidEOASignature = signer != address(0) && _isApprovedOrOwner(signer, tokenId); require( isValidEOASignature || Permit4494Lib._isValidContractERC1271Signature(_ownerOf(tokenId), hash, signature) || Permit4494Lib._isValidContractERC1271Signature(_getApproved(tokenId), hash, signature), "ERC721Permit: invalid signature" ); _approve(spender, tokenId); } function _getApproved(uint256 tokenId) internal view virtual returns (address) { if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector); return ERC721AStorage.layout()._tokenApprovals[tokenId].value; } function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { return _getApproved(tokenId) == spender || _isApprovedForAll(_ownerOf(tokenId), spender) || _ownerOf(tokenId) == spender; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { CountersUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { Permit4494Storage } from './Permit4494Storage.sol'; /// @title Permit4494Lib /// @author Martin Wawrusch for Roji Inc. /// @notice Contains utility functions for the permit implementation. library Permit4494Lib { using CountersUpgradeable for CountersUpgradeable.Counter; // solhint-disable-next-line var-name-mixedcase bytes32 internal constant PERMIT_4494_TYPEHASH = keccak256("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)"); /// Must be called after the token transfer in the ERC721A implementation /// but BEFORE the base code. /// /// @param startTokenId The first token id of the transfer /// @param quantity The number of tokens transferred. function _handleAfterTokenTransfers( uint256 startTokenId, uint256 quantity) internal { for (uint256 i = 0; i < quantity; i++) { Permit4494Storage.layout().nonces[startTokenId + i].increment(); } } function _isValidContractERC1271Signature( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector( IERC1271.isValidSignature.selector, hash, signature ) ); return (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; library Permit4494Storage { using CountersUpgradeable for CountersUpgradeable.Counter; struct Layout { mapping(uint256 => CountersUpgradeable.Counter) nonces; } bytes32 internal constant STORAGE_SLOT = keccak256('io.roji.facets.storage.Permit4494Storage'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; /// @title Versioned contract interface for ROJI. /// @author Martin Wawrusch for Roji Inc. /// @notice Returns the contract version, starting with 1, of the implementing contract. /// When inheriting from this contract you need to support EIP-165 as well. /// The interface id is /// bytes4 private constant _INTERFACE_ID_ROJI_VERSIONED_CONTRACT = bytes4(0xa0a8e460); interface IROJIVersionedContractFacet { /// @dev Returns the version of the underlying contract. function contractVersion() external pure returns (uint32); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IROJIVersionedContractFacet } from "./IROJIVersionedContractFacet.sol"; /// @title Exposes the contract version. /// @author Martin Wawrusch for Roji Inc. /// @notice This facet is hardcoded to 1 so include it in a dimamond if that diamond is in version 1. contract ROJIVersionedContractFacetV1 is IROJIVersionedContractFacet { /// @inheritdoc IROJIVersionedContractFacet function contractVersion() external pure returns (uint32) { return 1; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title RolesLib /// @author Martin Wawrusch for Roji Inc. /// @notice A collection of roles used within Animeme Labs contracts. library RolesLib { /// @dev Role used for anything touching finance (withdrawals, changing royalties etc) bytes32 internal constant ROLE_FINANCE = keccak256("ROLE_FINANCE"); /// @dev Role used for anything touching operations (pause etc) but not the access control admin, which is reserved for ROLE_ACCESS_CONTROL_ADMIN bytes32 internal constant ROLE_OPERATIONS = keccak256("ROLE_OPERATIONS"); /// @dev Role used to trigger the metadata update. bytes32 internal constant ROLE_METADATA_UPDATE = keccak256("ROLE_METADATA_UPDATE"); /// @dev Role used for anything touching manual minting. bytes32 internal constant ROLE_ADMIN_MINTING = keccak256("ROLE_ADMIN_MINTING"); /// @dev Role used for anything touching manual burning. bytes32 internal constant ROLE_ADMIN_BURNING = keccak256("ROLE_ADMIN_BURNING"); /// @dev Core role for managing access control. Holders of this role cam obtain full access to all /// aspects of the contract. bytes32 internal constant ROLE_ACCESS_CONTROL_ADMIN = bytes32(0); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title EIP-2981: NFT Royalty Standard /// @dev Interface for the NFT Royalty Standard /// https://eips.ethereum.org/EIPS/eip-2981 /// @custom:security-contact [email protected] interface IRoyaltiesERC2981Facet { /** * @dev Emitted when the defaultRoyaltyReceiver parameter is set to null. */ error DefaultRoyaltyReceiverIsNull(); /** * @dev Emitted when the defaultRoyaltyBPS parameter is above 10000. */ error RoyaltyBPSExceedsMax(); /// Emitted when the royalties tier has changed. /// @param oldDefaultRoyaltyReceiver The previous receiver. /// @param newDefaultRoyaltyReceiver The new receiver. /// @param oldDefaultRoyaltyBPS The previous BPS. /// @param newDefaultRoyaltyBPS The new BPS. event DefaultRoyaltyChanged(address indexed oldDefaultRoyaltyReceiver, address indexed newDefaultRoyaltyReceiver, uint16 oldDefaultRoyaltyBPS, uint16 newDefaultRoyaltyBPS); /// @notice Called with the sale price to determine how much royalty // is owed and to whom. /// @param _tokenId - the NFT asset queried for royalty information /// @param _salePrice - the sale price of the NFT asset specified by _tokenId /// @return receiver - address of who should be sent the royalty payment /// @return royaltyAmount - the royalty payment amount for _salePrice function royaltyInfo(uint256 _tokenId, uint256 _salePrice ) external view returns ( address receiver, uint256 royaltyAmount ); /// @notice Sets the default royalty receiver and default royalty base points (1/100 of a percent). /// @param defaultRoyaltyReceiver The account that receives the royalties. /// @param defaultRoyaltyBPS The base points (1/100 of a percent) of the default royalty. function setDefaultRoyalty(address defaultRoyaltyReceiver, uint16 defaultRoyaltyBPS) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { ERC2981Storage } from '@solidstate/contracts/token/common/ERC2981/ERC2981Storage.sol'; import { ERC2981Internal } from '@solidstate/contracts/token/common/ERC2981/ERC2981Internal.sol'; import { IRoyaltiesERC2981Facet } from "./IRoyaltiesERC2981Facet.sol"; import { RoyaltiesERC2981Lib } from "./RoyaltiesERC2981Lib.sol"; import { UsingAccessControl } from '../../facets/AccessControl/UsingAccessControl.sol'; /// @title Implementation of the EIP-2981: NFT Royalty Standard /// @author Martin Wawrusch for Roji Inc. /// @dev Inherits storage layout of ERC2981Storage. This facet uses access control. contract RoyaltiesERC2981FacetAccessControl is ERC2981Internal, UsingAccessControl, IRoyaltiesERC2981Facet { /// @inheritdoc IRoyaltiesERC2981Facet function royaltyInfo(uint256 tokenId, uint256 salePrice) public view returns (address, uint256) { return _royaltyInfo(tokenId, salePrice); } /// @inheritdoc IRoyaltiesERC2981Facet function setDefaultRoyalty(address defaultRoyaltyReceiver, uint16 defaultRoyaltyBPS) external onlyAccessControlFinance { if(defaultRoyaltyReceiver == address(0x0)){ revert DefaultRoyaltyReceiverIsNull(); } if(defaultRoyaltyBPS > 10000){ revert RoyaltyBPSExceedsMax(); } emit DefaultRoyaltyChanged(ERC2981Storage.layout().defaultRoyaltyReceiver, defaultRoyaltyReceiver, ERC2981Storage.layout().defaultRoyaltyBPS, defaultRoyaltyBPS); RoyaltiesERC2981Lib._setDefaultRoyalty(defaultRoyaltyReceiver, defaultRoyaltyBPS); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { ERC2981Storage } from '@solidstate/contracts/token/common/ERC2981/ERC2981Storage.sol'; import { ERC2981Internal } from '@solidstate/contracts/token/common/ERC2981/ERC2981Internal.sol'; import { IRoyaltiesERC2981Facet } from "./IRoyaltiesERC2981Facet.sol"; library RoyaltiesERC2981Lib { function _setDefaultRoyalty(address defaultRoyaltyReceiver, uint16 defaultRoyaltyBPS) internal { ERC2981Storage.layout().defaultRoyaltyBPS = defaultRoyaltyBPS; ERC2981Storage.layout().defaultRoyaltyReceiver = defaultRoyaltyReceiver; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title IWithdrawFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Provides the ability to withdraw funds from the contract. This is used as 'Black Hole Protection' to be able to refund users who inadvertently send funds or tokens to the contract. interface IWithdrawFacet { /// @notice Withdraws ETH from the contract. /// @dev This is to be used to withdraw the ETH that was sent to the contract as payment for the NFTs. function withdraw() external; /// @notice Withdraws ERC20 tokens from the contract. /// @param tokenAddress The address of the ERC20 token contract. /// @dev This is to be used to withdraw the ERC20 tokens (USDC, etc) that were sent to the contract as payment for the NFTs. function withdrawERC20(address tokenAddress) external; /// @notice Blackhole protection against accidentally transferred NFTs. /// @param tokenAddress The address of the NFT contract. /// @param tokenId The ID of the NFT to withdraw. /// @dev This is a fallback in case the contract receives 721 NFTs directly. function withdrawERC721(address tokenAddress, uint256 tokenId) external; /// @notice Blackhole protection against accidentally transferred NFTs. /// @param tokenAddress The address of the NFT contract. /// @param tokenId The ID of the NFT to withdraw. /// @param value The amount of ERC1155 tokens to withdraw. /// @dev This is a fallback in case the contract receives 721 NFTs directly. function withdrawERC1155(address tokenAddress, uint256 tokenId, uint256 value) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IWithdrawFacet } from "./IWithdrawFacet.sol"; import { IERC20 } from "@solidstate/contracts/interfaces/IERC20.sol"; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import { SafeERC20 } from "@solidstate/contracts/utils/SafeERC20.sol"; import { UsingAccessControl } from "../../facets/AccessControl/UsingAccessControl.sol"; /// @title WithdrawFacet /// @author Martin Wawrusch for Roji Inc. /// @notice Provides the ability to withdraw funds from the contract. This is used as 'Black Hole Protection' to be able to refund users who inadvertently send funds or tokens to the contract. /// Access is restricted to the special ROLE_ROJI_BLACKHOLE_WITHDRAWER role to prevent abuse. contract WithdrawFacetAccessControl is UsingAccessControl , IWithdrawFacet { using SafeERC20 for IERC20; /// @inheritdoc IWithdrawFacet function withdraw() external onlyAccessControlFinance { // (bool sent, ) = msg.sender.call{value: address(this).balance}(""); // require(sent, "Failed to send ether"); payable(msg.sender).transfer(address(this).balance); } /// @inheritdoc IWithdrawFacet function withdrawERC20(address tokenAddress) external onlyAccessControlFinance { IERC20 token = IERC20(tokenAddress); token.safeTransfer(msg.sender, token.balanceOf(address(this))); } /// @inheritdoc IWithdrawFacet function withdrawERC721(address tokenAddress, uint256 tokenId) external onlyAccessControlFinance { IERC721 token = IERC721(tokenAddress); token.transferFrom(address(this), msg.sender, tokenId); } /// @inheritdoc IWithdrawFacet function withdrawERC1155(address tokenAddress, uint256 tokenId, uint256 value) external onlyAccessControlFinance { IERC1155 token = IERC1155(tokenAddress); token.safeTransferFrom(address(this), msg.sender, tokenId, value, ""); } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; // The following is imported so Hardhat/typechain can recognize it. import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; /// @title EIP-2981: NFT Royalty Standard /// @dev Interface for the NFT Royalty Standard /// https://eips.ethereum.org/EIPS/eip-2981 /// @custom:security-contact [email protected] interface IERC2981 { /// @notice Called with the sale price to determine how much royalty // is owed and to whom. /// @param _tokenId - the NFT asset queried for royalty information /// @param _salePrice - the sale price of the NFT asset specified by _tokenId /// @return receiver - address of who should be sent the royalty payment /// @return royaltyAmount - the royalty payment amount for _salePrice function royaltyInfo( uint256 _tokenId, uint256 _salePrice ) external view returns ( address receiver, uint256 royaltyAmount ); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; /// @title EIP-721 Metadata Update Extension interface IERC4906 /* is IERC165, IERC721 */ { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.19; /// @title ROJIInterfacesLib /// @author Martin Wawrusch for Roji Inc. /// @notice Exportes all interface IDs used by ROJI library ROJIInterfacesLib { /// @dev Interface ID for ERC721 - NFTs bytes4 internal constant INTERFACE_ID_ERC721 = bytes4(0x80ac58cd); /// @dev Interface ID for ERC721_METADATA - NFT metadata bytes4 internal constant INTERFACE_ID_ERC721_METADATA = bytes4(0x5b5e139f); /// @dev Interface ID for ERC4494 721NFT Permit functionality bytes4 internal constant INTERFACE_ID_ERC4494 = bytes4(0x5604e225); /// @dev Interface ID for ERC2981 - royalties bytes4 internal constant INTERFACE_ID_ERC2981 = bytes4(0x2a55205a); /// @dev Interface ID for `IROJIVersionedContract` bytes4 internal constant INTERFACE_ID_ROJI_VERSIONED_CONTRACT = bytes4(0xa0a8e460); /// @dev Interface ID for ERC4494 721NFT Permit functionality bytes4 internal constant INTERFACE_ID_IERC4906 = bytes4(0x49064906); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; // import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; // contract MockUSDC is ERC20, ERC20Permit { // constructor() ERC20("MockUSDC", "USDC") ERC20Permit("MockUSDC") {} // function mint(address to, uint256 amount) public { // _mint(to, amount); // } // } import "solmate/src/tokens/ERC20.sol"; contract MockUSDC is ERC20 { constructor() ERC20("MOCK USDC", "USDC", 6) {} function mint(address to, uint256 amount) public { _mint(to, amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 * * Implementation of a diamond. /******************************************************************************/ import {LibDiamond} from "./libraries/LibDiamond.sol"; import {IDiamondCut} from "./interfaces/IDiamondCut.sol"; contract Diamond { struct Initialization { address initContract; bytes initData; } /// @notice This construct a diamond contract /// @param _contractOwner the owner of the contract. With default DiamondCutFacet, this is the sole address allowed to make further cuts. /// @param _diamondCut the list of facet to add /// @param _initializations the list of initialization pair to execute. This allow to setup a contract with multiple level of independent initialization. constructor( address _contractOwner, IDiamondCut.FacetCut[] memory _diamondCut, Initialization[] memory _initializations ) payable { if (_contractOwner != address(0)) { LibDiamond.setContractOwner(_contractOwner); } LibDiamond.diamondCut(_diamondCut, address(0), ""); for (uint256 i = 0; i < _initializations.length; i++) { LibDiamond.initializeDiamondCut(_initializations[i].initContract, _initializations[i].initData); } } // Find facet for function that is called and execute the // function if a facet is found and return any value. fallback() external payable { LibDiamond.DiamondStorage storage ds; bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; // get diamond storage assembly { ds.slot := position } // get facet from function selector address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress; require(facet != address(0), "Diamond: Function does not exist"); // Execute external function from facet using delegatecall and return any value. assembly { // copy function selector and any arguments calldatacopy(0, 0, calldatasize()) // execute function call using the facet let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) // get any return value returndatacopy(0, 0, returndatasize()) // return any return value or error back to the caller switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } receive() external payable {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ interface IDiamondCut { enum FacetCutAction {Add, Replace, Remove} // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; FacetCutAction action; bytes4[] functionSelectors; } /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; library LibDiamond { bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage"); struct FacetAddressAndPosition { address facetAddress; uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array } struct FacetFunctionSelectors { bytes4[] functionSelectors; uint256 facetAddressPosition; // position of facetAddress in facetAddresses array } struct DiamondStorage { // maps function selector to the facet address and // the position of the selector in the facetFunctionSelectors.selectors array mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition; // maps facet addresses to function selectors mapping(address => FacetFunctionSelectors) facetFunctionSelectors; // facet addresses address[] facetAddresses; // Used to query if a contract implements an interface. // Used to implement ERC-165. mapping(bytes4 => bool) supportedInterfaces; // owner of the contract address contractOwner; } function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } } event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); } function contractOwner() internal view returns (address contractOwner_) { contractOwner_ = diamondStorage().contractOwner; } function enforceIsContractOwner() internal view { require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner"); } event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata); // Internal function version of diamondCut function diamondCut( IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata ) internal { for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) { IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action; if (action == IDiamondCut.FacetCutAction.Add) { addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Replace) { replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Remove) { removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else { revert("LibDiamondCut: Incorrect FacetCutAction"); } } emit DiamondCut(_diamondCut, _init, _calldata); initializeDiamondCut(_init, _calldata); } function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists"); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function"); removeFunction(ds, oldFacetAddress, selector); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); // if function does not exist then do nothing and return require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)"); for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; removeFunction(ds, oldFacetAddress, selector); } } function addFacet(DiamondStorage storage ds, address _facetAddress) internal { enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code"); ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length; ds.facetAddresses.push(_facetAddress); } function addFunction(DiamondStorage storage ds, bytes4 _selector, uint96 _selectorPosition, address _facetAddress) internal { ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition; ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector); ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress; } function removeFunction(DiamondStorage storage ds, address _facetAddress, bytes4 _selector) internal { require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist"); // an immutable function is a function defined directly in a diamond require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function"); // replace selector with last selector, then delete last selector uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition; uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1; // if not the same then replace _selector with lastSelector if (selectorPosition != lastSelectorPosition) { bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition]; ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector; ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(selectorPosition); } // delete the last selector ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop(); delete ds.selectorToFacetAndPosition[_selector]; // if no more selectors for facet address then delete the facet address if (lastSelectorPosition == 0) { // replace facet address with last facet address and delete last facet address uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1; uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; if (facetAddressPosition != lastFacetAddressPosition) { address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition]; ds.facetAddresses[facetAddressPosition] = lastFacetAddress; ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = facetAddressPosition; } ds.facetAddresses.pop(); delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; } } function initializeDiamondCut(address _init, bytes memory _calldata) internal { if (_init == address(0)) { require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty"); } else { require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)"); if (_init != address(this)) { enforceHasContractCode(_init, "LibDiamondCut: _init address has no code"); } (bool success, bytes memory error) = _init.delegatecall(_calldata); if (!success) { if (error.length > 0) { // bubble up the error revert(string(error)); } else { revert("LibDiamondCut: _init function reverted"); } } } } function enforceHasContractCode(address _contract, string memory _errorMessage) internal view { uint256 contractSize; assembly { contractSize := extcodesize(_contract) } require(contractSize > 0, _errorMessage); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./libraries/LibDiamond.sol"; contract UsingDiamondOwner { modifier onlyOwner() { LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); require(msg.sender == ds.contractOwner, "Only owner is allowed to perform this action"); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; interface IOperatorFilterRegistry { /** * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns * true if supplied registrant address is not registered. */ function isOperatorAllowed(address registrant, address operator) external view returns (bool); /** * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner. */ function register(address registrant) external; /** * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes. */ function registerAndSubscribe(address registrant, address subscription) external; /** * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another * address without subscribing. */ function registerAndCopyEntries(address registrant, address registrantToCopy) external; /** * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner. * Note that this does not remove any filtered addresses or codeHashes. * Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes. */ function unregister(address addr) external; /** * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered. */ function updateOperator(address registrant, address operator, bool filtered) external; /** * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates. */ function updateOperators(address registrant, address[] calldata operators, bool filtered) external; /** * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered. */ function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external; /** * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates. */ function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external; /** * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous * subscription if present. * Note that accounts with subscriptions may go on to subscribe to other accounts - in this case, * subscriptions will not be forwarded. Instead the former subscription's existing entries will still be * used. */ function subscribe(address registrant, address registrantToSubscribe) external; /** * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes. */ function unsubscribe(address registrant, bool copyExistingEntries) external; /** * @notice Get the subscription address of a given registrant, if any. */ function subscriptionOf(address addr) external returns (address registrant); /** * @notice Get the set of addresses subscribed to a given registrant. * Note that order is not guaranteed as updates are made. */ function subscribers(address registrant) external returns (address[] memory); /** * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant. * Note that order is not guaranteed as updates are made. */ function subscriberAt(address registrant, uint256 index) external returns (address); /** * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr. */ function copyEntriesOf(address registrant, address registrantToCopy) external; /** * @notice Returns true if operator is filtered by a given address or its subscription. */ function isOperatorFiltered(address registrant, address operator) external returns (bool); /** * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription. */ function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool); /** * @notice Returns true if a codeHash is filtered by a given address or its subscription. */ function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool); /** * @notice Returns a list of filtered operators for a given address or its subscription. */ function filteredOperators(address addr) external returns (address[] memory); /** * @notice Returns the set of filtered codeHashes for a given address or its subscription. * Note that order is not guaranteed as updates are made. */ function filteredCodeHashes(address addr) external returns (bytes32[] memory); /** * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or * its subscription. * Note that order is not guaranteed as updates are made. */ function filteredOperatorAt(address registrant, uint256 index) external returns (address); /** * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or * its subscription. * Note that order is not guaranteed as updates are made. */ function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32); /** * @notice Returns true if an address has registered */ function isRegistered(address addr) external returns (bool); /** * @dev Convenience method to compute the code hash of an arbitrary contract */ function codeHashOf(address addr) external returns (bytes32); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": { "": { "__CACHE_BREAKER__": "0x00000000d41867734bbee4c6863d9255b2b06ac1" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_contractOwner","type":"address"},{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"enum IDiamondCut.FacetCutAction","name":"action","type":"uint8"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"internalType":"struct IDiamondCut.FacetCut[]","name":"_diamondCut","type":"tuple[]"},{"components":[{"internalType":"address","name":"initContract","type":"address"},{"internalType":"bytes","name":"initData","type":"bytes"}],"internalType":"struct Diamond.Initialization[]","name":"_initializations","type":"tuple[]"}],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"enum IDiamondCut.FacetCutAction","name":"action","type":"uint8"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"indexed":false,"internalType":"struct IDiamondCut.FacetCut[]","name":"_diamondCut","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"_init","type":"address"},{"indexed":false,"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"DiamondCut","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405260405161176138038061176183398101604081905261002291611206565b8282826001600160a01b0383161561003d5761003d836100ce565b61005c825f60405180602001604052805f81525061014f60201b60201c565b5f5b81518110156100c2576100b082828151811061007c5761007c6113ae565b60200260200101515f0151838381518110610099576100996113ae565b60200260200101516020015161037160201b60201c565b806100ba816113d6565b91505061005e565b505050505050506115b6565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c132080546001600160a01b031981166001600160a01b038481169182179093556040515f805160206116b5833981519152939092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f5b8351811015610326575f84828151811061016d5761016d6113ae565b60200260200101516020015190505f600281111561018d5761018d6113ee565b81600281111561019f5761019f6113ee565b036101f2576101ed8583815181106101b9576101b96113ae565b60200260200101515f01518684815181106101d6576101d66113ae565b60200260200101516040015161057f60201b60201c565b610313565b6001816002811115610206576102066113ee565b03610254576101ed858381518110610220576102206113ae565b60200260200101515f015186848151811061023d5761023d6113ae565b6020026020010151604001516107ee60201b60201c565b6002816002811115610268576102686113ee565b036102b6576101ed858381518110610282576102826113ae565b60200260200101515f015186848151811061029f5761029f6113ae565b602002602001015160400151610a6660201b60201c565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b60648201526084015b60405180910390fd5b508061031e816113d6565b915050610151565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67383838360405161035a9392919061142d565b60405180910390a161036c8282610371565b505050565b6001600160a01b0382166103f8578051156103f45760405162461bcd60e51b815260206004820152603c60248201527f4c69624469616d6f6e644375743a205f696e697420697320616464726573732860448201527f3029206275745f63616c6c64617461206973206e6f7420656d70747900000000606482015260840161030a565b5050565b5f81511161046e5760405162461bcd60e51b815260206004820152603d60248201527f4c69624469616d6f6e644375743a205f63616c6c6461746120697320656d707460448201527f7920627574205f696e6974206973206e6f742061646472657373283029000000606482015260840161030a565b6001600160a01b03821630146104a0576104a0826040518060600160405280602881526020016116d560289139610bb1565b5f80836001600160a01b0316836040516104ba9190611528565b5f60405180830381855af49150503d805f81146104f2576040519150601f19603f3d011682016040523d82523d5f602084013e6104f7565b606091505b50915091508161057957805115610522578060405162461bcd60e51b815260040161030a9190611543565b60405162461bcd60e51b815260206004820152602660248201527f4c69624469616d6f6e644375743a205f696e69742066756e6374696f6e2072656044820152651d995c9d195960d21b606482015260840161030a565b50505050565b5f8151116105d05760405162461bcd60e51b815260206004820152602b60248201525f8051602061174183398151915260448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161030a565b5f805160206116b58339815191526001600160a01b0383166106365760405162461bcd60e51b815260206004820152602c60248201525f805160206116fd83398151915260448201526b65206164647265737328302960a01b606482015260840161030a565b6001600160a01b0383165f908152600182016020526040812054906001600160601b038216900361066b5761066b8285610bd2565b5f5b83518110156107e7575f848281518110610689576106896113ae565b6020908102919091018101516001600160e01b031981165f908152918690526040909120549091506001600160a01b0316801561072e5760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60448201527f6e207468617420616c7265616479206578697374730000000000000000000000606482015260840161030a565b6001600160e01b031982165f8181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b031916179055836107cf8161155c565b945050505080806107df906113d6565b91505061066d565b5050505050565b5f81511161083f5760405162461bcd60e51b815260206004820152602b60248201525f8051602061174183398151915260448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161030a565b5f805160206116b58339815191526001600160a01b0383166108a55760405162461bcd60e51b815260206004820152602c60248201525f805160206116fd83398151915260448201526b65206164647265737328302960a01b606482015260840161030a565b6001600160a01b0383165f908152600182016020526040812054906001600160601b03821690036108da576108da8285610bd2565b5f5b83518110156107e7575f8482815181106108f8576108f86113ae565b6020908102919091018101516001600160e01b031981165f908152918690526040909120549091506001600160a01b0390811690871681036109a25760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e0000000000000000606482015260840161030a565b6109ad858284610c3b565b6001600160e01b031982165f8181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b03191617905583610a4e8161155c565b94505050508080610a5e906113d6565b9150506108dc565b5f815111610ab75760405162461bcd60e51b815260206004820152602b60248201525f8051602061174183398151915260448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161030a565b5f805160206116b58339815191526001600160a01b03831615610b425760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260448201527f657373206d757374206265206164647265737328302900000000000000000000606482015260840161030a565b5f5b8251811015610579575f838281518110610b6057610b606113ae565b6020908102919091018101516001600160e01b031981165f908152918590526040909120549091506001600160a01b0316610b9c848284610c3b565b50508080610ba9906113d6565b915050610b44565b813b81816105795760405162461bcd60e51b815260040161030a9190611543565b610bf48160405180606001604052806024815260200161171d60249139610bb1565b6002820180546001600160a01b039092165f8181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160a01b038216610cb75760405162461bcd60e51b815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e2774206578697374000000000000000000606482015260840161030a565b306001600160a01b03831603610d265760405162461bcd60e51b815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201526d3a30b1363290333ab731ba34b7b760911b606482015260840161030a565b6001600160e01b031981165f90815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b03169291610d7491611589565b9050808214610e63576001600160a01b0384165f9081526001860160205260408120805483908110610da857610da86113ae565b5f91825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b925082919085908110610df857610df86113ae565b5f91825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b0384165f9081526001860160205260409020805480610e8b57610e8b6115a2565b5f828152602080822060085f1990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b031985168252869052604081208190558190036107e75760028501545f90610eeb90600190611589565b6001600160a01b0386165f908152600180890160205260409091200154909150808214610f96575f876002018381548110610f2857610f286113ae565b5f918252602090912001546002890180546001600160a01b039092169250829184908110610f5857610f586113ae565b5f91825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b86600201805480610fa957610fa96115a2565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b80516001600160a01b0381168114611006575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b03811182821017156110415761104161100b565b60405290565b604051606081016001600160401b03811182821017156110415761104161100b565b604051601f8201601f191681016001600160401b03811182821017156110915761109161100b565b604052919050565b5f6001600160401b038211156110b1576110b161100b565b5060051b60200190565b5f5b838110156110d55781810151838201526020016110bd565b50505f910152565b5f601f83818401126110ed575f80fd5b825160206111026110fd83611099565b611069565b82815260059290921b85018101918181019087841115611120575f80fd5b8287015b848110156111fa5780516001600160401b0380821115611143575f8081fd5b908901906040601f19838d03810182131561115d575f8081fd5b61116561101f565b611170898601610ff0565b81528285015184811115611183575f8081fd5b8086019550508d603f860112611198575f8081fd5b88850151848111156111ac576111ac61100b565b6111bb8a848e84011601611069565b94508085528e848288010111156111d3575f92508283fd5b6111e2818b87018689016110bb565b50808901939093525050845250918301918301611124565b50979650505050505050565b5f805f60608486031215611218575f80fd5b61122184610ff0565b60208501519093506001600160401b038082111561123d575f80fd5b818601915086601f830112611250575f80fd5b815161125e6110fd82611099565b8082825260208201915060208360051b86010192508983111561127f575f80fd5b602085015b8381101561137e5780518581111561129a575f80fd5b86016060818d03601f190112156112af575f80fd5b6112b7611047565b6112c360208301610ff0565b81526040820151600381106112d6575f80fd5b60208201526060820151878111156112ec575f80fd5b8083019250508c603f830112611300575f80fd5b60208201516113116110fd82611099565b81815260059190911b83016040019060208101908f831115611331575f80fd5b6040850194505b828510156113685784516001600160e01b031981168114611357575f80fd5b825260209485019490910190611338565b6040840152505084525060209283019201611284565b5060408901519096509350505080821115611397575f80fd5b506113a4868287016110dd565b9150509250925092565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016113e7576113e76113c2565b5060010190565b634e487b7160e01b5f52602160045260245ffd5b5f81518084526114198160208601602086016110bb565b601f01601f19169290920160200192915050565b5f6060808301818452808751808352608092508286019150828160051b8701016020808b015f5b848110156114f857898403607f19018652815180516001600160a01b0316855283810151898601906003811061149857634e487b7160e01b5f52602160045260245ffd5b868601526040918201519186018a9052815190819052908401905f90898701905b808310156114e35783516001600160e01b03191682529286019260019290920191908601906114b9565b50978501979550505090820190600101611454565b50506001600160a01b038a1690880152868103604088015261151a8189611402565b9a9950505050505050505050565b5f82516115398184602087016110bb565b9190910192915050565b602081525f6115556020830184611402565b9392505050565b5f6001600160601b038281166002600160601b0319810161157f5761157f6113c2565b6001019392505050565b8181038181111561159c5761159c6113c2565b92915050565b634e487b7160e01b5f52603160045260245ffd5b60f3806115c25f395ff3fe608060405236600a57005b5f80356001600160e01b03191681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c602081905260409091205481906001600160a01b03168060a05760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f74206578697374604482015260640160405180910390fd5b365f80375f80365f845af43d5f803e80801560b9573d5ff35b3d5ffdfea26469706673582212207d6f48d28f520ff8f0bf90a925b891aec0a995eecbb719894f59f80949af468264736f6c63430008140033c8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204164642066616365742063616e277420624c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f64654c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e2066000000000000000000000000328424e95ec34cc062627508efe55ad01988adab0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000064697054de83c08bc72a4370843f1127dce5642a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001f57e829100000000000000000000000000000000000000000000000000000000000000000000000000000000429dbde7913c0ed51e4b21163760b92ee66ff5f50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000011f931c1c000000000000000000000000000000000000000000000000000000000000000000000000000000003bcf4185443a339517ad4e580067f178d1b68e1d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000005cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000001ffc9a700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000e68d85348f227d2ebee814c38918f8a2d7d9b603000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a42a84809100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000148e2b0930000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064697054de83c08bc72a4370843f1127dce5642a00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000044f57e8291000000000000000000000000328424e95ec34cc062627508efe55ad01988adab000000000000000000000000328424e95ec34cc062627508efe55ad01988adab00000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405236600a57005b5f80356001600160e01b03191681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c602081905260409091205481906001600160a01b03168060a05760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f74206578697374604482015260640160405180910390fd5b365f80375f80365f845af43d5f803e80801560b9573d5ff35b3d5ffdfea26469706673582212207d6f48d28f520ff8f0bf90a925b891aec0a995eecbb719894f59f80949af468264736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000328424e95ec34cc062627508efe55ad01988adab0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000064697054de83c08bc72a4370843f1127dce5642a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001f57e829100000000000000000000000000000000000000000000000000000000000000000000000000000000429dbde7913c0ed51e4b21163760b92ee66ff5f50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000011f931c1c000000000000000000000000000000000000000000000000000000000000000000000000000000003bcf4185443a339517ad4e580067f178d1b68e1d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000005cdffacc60000000000000000000000000000000000000000000000000000000052ef6b2c00000000000000000000000000000000000000000000000000000000adfca15e000000000000000000000000000000000000000000000000000000007a0ed6270000000000000000000000000000000000000000000000000000000001ffc9a700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000e68d85348f227d2ebee814c38918f8a2d7d9b603000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a42a84809100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000148e2b0930000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064697054de83c08bc72a4370843f1127dce5642a00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000044f57e8291000000000000000000000000328424e95ec34cc062627508efe55ad01988adab000000000000000000000000328424e95ec34cc062627508efe55ad01988adab00000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _contractOwner (address): 0x328424E95EC34CC062627508efE55ad01988adAb
Arg [1] : _diamondCut (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : _initializations (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
44 Constructor Arguments found :
Arg [0] : 000000000000000000000000328424e95ec34cc062627508efe55ad01988adab
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000340
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [6] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [7] : 00000000000000000000000064697054de83c08bc72a4370843f1127dce5642a
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [11] : f57e829100000000000000000000000000000000000000000000000000000000
Arg [12] : 000000000000000000000000429dbde7913c0ed51e4b21163760b92ee66ff5f5
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [16] : 1f931c1c00000000000000000000000000000000000000000000000000000000
Arg [17] : 0000000000000000000000003bcf4185443a339517ad4e580067f178d1b68e1d
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [21] : cdffacc600000000000000000000000000000000000000000000000000000000
Arg [22] : 52ef6b2c00000000000000000000000000000000000000000000000000000000
Arg [23] : adfca15e00000000000000000000000000000000000000000000000000000000
Arg [24] : 7a0ed62700000000000000000000000000000000000000000000000000000000
Arg [25] : 01ffc9a700000000000000000000000000000000000000000000000000000000
Arg [26] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [28] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [29] : 000000000000000000000000e68d85348f227d2ebee814c38918f8a2d7d9b603
Arg [30] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [31] : 00000000000000000000000000000000000000000000000000000000000000a4
Arg [32] : 2a84809100000000000000000000000000000000000000000000000000000000
Arg [33] : 0000004000000000000000000000000000000000000000000000000000000000
Arg [34] : 0000008000000000000000000000000000000000000000000000000000000000
Arg [35] : 0000000148e2b093000000000000000000000000000000000000000000000000
Arg [36] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [37] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [38] : 00000000000000000000000064697054de83c08bc72a4370843f1127dce5642a
Arg [39] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [40] : 0000000000000000000000000000000000000000000000000000000000000044
Arg [41] : f57e8291000000000000000000000000328424e95ec34cc062627508efe55ad0
Arg [42] : 1988adab000000000000000000000000328424e95ec34cc062627508efe55ad0
Arg [43] : 1988adab00000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.