ERC-721
NFT
Overview
Max Total Supply
3,333 MoZ
Holders
1,223
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 MoZLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
ZeeMasks
Compiler Version
v0.8.14+commit.80d49f37
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.8.14; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "./abstract/Whitelist.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; contract ZeeMasks is ERC721, ERC721Enumerable, Ownable, Whitelist { /// @notice Emitted when the merkle root has been set. event MerkleRootSet(bytes32 merkleRoot); bool public mintIsActive = false; string private _baseURIextended; bytes32 internal _whitelistMerkleRoot; uint256 private publiclyMinted = 0; uint256 private fireClass = 0; uint256 private waterClass = 0; uint256 private grassClass = 0; uint256 public constant MAX_SUPPLY = 3333; uint256 public constant MAX_PUBLIC_MINT = 3000; mapping(address => bool) private minters; constructor() ERC721("Mask of ZEE", "MoZ") { } function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) { super._beforeTokenTransfer(from, to, tokenId); } function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) { return super.supportsInterface(interfaceId); } function setBaseURI(string memory baseURI_) external onlyOwner() { _baseURIextended = baseURI_; } function _baseURI() internal view virtual override returns (string memory) { return _baseURIextended; } function reserve(uint256 n) external onlyOwner { uint supply = totalSupply(); uint i; for (i = 0; i < n; i++) { _safeMint(msg.sender, supply + i); } } function setMintState(bool newState) external onlyOwner { mintIsActive = newState; } function canMint(address account) external view returns(bool) { return minters[account] == false; } function mint(bytes32[] memory whitelistProof) external { uint256 ts = totalSupply(); require(minters[msg.sender] == false, "Only single item can be minted per wallet"); require(mintIsActive, "Minting not yet activated"); require(ts < MAX_SUPPLY, "Mint would exceed max tokens"); require(publiclyMinted < MAX_PUBLIC_MINT, "All tokens minted"); require(_isValidMerkleProof(msg.sender, whitelistProof), "Wallet not whitelisted"); minters[msg.sender] = true; _safeMint(msg.sender, ts); publiclyMinted++; } function withdraw() external onlyOwner { uint balance = address(this).balance; payable(msg.sender).transfer(balance); } /// @inheritdoc IWhitelist function setWhitelistMerkleRoot(bytes32 merkleRoot) external override onlyOwner { _whitelistMerkleRoot = merkleRoot; emit MerkleRootSet(merkleRoot); } /// @inheritdoc IWhitelist function getWhitelistMerkleRoot() external view override returns (bytes32) { return _getWhitelistMerkleRoot(); } /// @inheritdoc Whitelist function _getWhitelistMerkleRoot() internal view override returns (bytes32) { return _whitelistMerkleRoot; } /// @inheritdoc IWhitelist function isUserWhitelisted(address account, bytes32[] memory whitelistProof) external view override returns (bool) { return _isValidMerkleProof(account, whitelistProof); } function publiclyMintedTokens() external view returns (uint256) { return publiclyMinted; } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, Strings.toString(tokenId))) : ""; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@openzeppelin/contracts/utils/StorageSlot.sol"; import "./IAccessControlled.sol"; import "../Roles.sol"; import "../IACL.sol"; /// @notice Modifier provider for contracts that want to interact with the ACL contract. abstract contract AccessControlledUpgradeable is IAccessControlled, ContextUpgradeable { bytes32 private constant _ACL_SLOT = bytes32(uint256(keccak256("zee-game.acl.slot")) - 1); modifier onlyRole(bytes32 role) { _getAcl().checkRole(role, _msgSender()); _; } /// @dev Modifier to make a function callable by the admin account. modifier onlyAdmin() { _getAcl().checkRole(Roles.ADMIN, _msgSender()); _; } /// @dev Modifier to make a function callable by a supervisor account. modifier onlyMaintainer() { _getAcl().checkRole(Roles.MAINTAINER, _msgSender()); _; } function __AccessControlled_init(address acl) internal onlyInitializing { // solhint-disable-previous-line func-name-mixedcase // TODO check ACL interface StorageSlot.getAddressSlot(_ACL_SLOT).value = acl; } /// @inheritdoc IAccessControlled function getACL() external view returns (address) { // solhint-disable-previous-line ordering return address(_getAcl()); } /// @dev return the IACL address function _getAcl() internal view returns (IACL) { return IACL(StorageSlot.getAddressSlot(_ACL_SLOT).value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; /// @notice Access Control List contract interface. interface IAccessControlled { /// @notice Get the ACL contract address. /// @return The ACL contract address. function getACL() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; /// @notice Different role definitions used by the ACL contract. library Roles { /// @dev This maps directly to the OpenZeppelins AccessControl DEFAULT_ADMIN bytes32 public constant ADMIN = 0x00; /// @dev The Maintainer role. Can execute Maintainer-only tasks. bytes32 public constant MAINTAINER = keccak256("MAINTAINER_ROLE"); /// @dev The NFT owner role. Can execute NFT-only tasks. bytes32 public constant NFT_OWNER = keccak256("NFT_OWNER"); /// @dev The auxiliary contracts that can perform cross-calls with one another. // TODO: segregate these into a smaller roles. bytes32 public constant AUXILIARY_CONTRACTS = keccak256("AUXILIARY_CONTRACTS"); /// @dev The Fragment mini-game burn permission bytes32 public constant FRAGMENT_MINI_GAME_BURN = keccak256("FRAGMENT_MINI_GAME_BURN"); /// @dev The Zee NFT mint permission bytes32 public constant ZEE_NFT_MINT = keccak256("ZEE_NFT_MINT"); /// @dev The Zee NFT burn permission bytes32 public constant ZEE_NFT_BURN = keccak256("ZEE_NFT_BURN"); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts-upgradeable/access/IAccessControlEnumerableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol"; /// @notice Access Control List contract interface. interface IACL is IAccessControlEnumerableUpgradeable { error RolesContractIncorrectlyConfigured(); error CannotHaveMoreThanOneAddressInRole(); error CannotRemoveLastAdmin(); /// @notice revert if the `account` does not have the specified role. /// @param role the role specifier. /// @param account the address to check the role for. function checkRole(bytes32 role, address account) external view; /// @notice Get the admin role describing bytes. /// @return role bytes. function getAdminRole() external pure returns (bytes32); /// @notice Get the maintainer role describing bytes. /// @return role bytes. function getMaintainerRole() external pure returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.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] * ``` * 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. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = _setInitializedVersion(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. * * `initializer` is equivalent to `reinitializer(1)`, so 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. * * 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. */ modifier reinitializer(uint8 version) { bool isTopLevelCall = _setInitializedVersion(version); if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _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. */ function _disableInitializers() internal virtual { _setInitializedVersion(type(uint8).max); } function _setInitializedVersion(uint8 version) private returns (bool) { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level // of initializers, because in other contexts the contract may have been reentered. if (_initializing) { require( version == 1 && !AddressUpgradeable.isContract(address(this)), "Initializable: contract is already initialized" ); return false; } else { require(_initialized < version, "Initializable: contract is already initialized"); _initialized = version; return true; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable { /** * @dev 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); /** * @dev 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); }
// 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 IERC165Upgradeable { /** * @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 v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableMapUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol"; import "../acl/access-controlled/AccessControlledUpgradeable.sol"; import "../common/BlockAware.sol"; import "./IFragmentMiniGame.sol"; import "./FragmentMiniGameStorage.sol"; import "./FragmentMiniGameUtils.sol"; contract FragmentMiniGame is IFragmentMiniGame, ERC1155Upgradeable, ERC1155BurnableUpgradeable, UUPSUpgradeable, AccessControlledUpgradeable, BlockAware, FragmentMiniGameStorage { using EnumerableMapUpgradeable for EnumerableMapUpgradeable.Bytes32ToBytes32Map; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set; using FragmentMiniGameUtils for FragmentGroup; using FragmentMiniGameUtils for bytes16; using FragmentMiniGameUtils for string; using FragmentMiniGameUtils for uint256; using FragmentMiniGameUtils for bytes32; using StringsUpgradeable for uint256; /// @dev Modifier for making sure that the group does not exist. modifier whenGroupDoesNotExist(string memory groupName) { bytes16 groupId = groupName.toGroupId(); _checkGroupDoesNotExist(groupId); _; } /// @dev Modifier for making sure that the fragment group exists. modifier whenFragmentGroupExists(string memory groupName) { bytes16 groupId = groupName.toGroupId(); _checkFragmentGroupExists(groupId); _; } /// @dev Modifier for making sure that the object group exists. modifier whenObjectGroupExists(string memory groupName) { bytes16 groupId = groupName.toGroupId(); _checkObjectGroupExists(groupId); _; } /// @dev Constructor that gets called for the implementation contract. constructor() initializer { // solhint-disable-previous-line no-empty-blocks } // solhint-disable-next-line comprehensive-interface function initialize( address acl, string calldata baseUri, string calldata name_, string calldata symbol_ ) external initializer { __BlockAware_init(); __UUPSUpgradeable_init(); __AccessControlled_init(acl); __ERC1155_init(baseUri); // Set metadata _name = name_; _symbol = symbol_; // Set the base URI _setBaseURI(baseUri); } /// @inheritdoc IFragmentMiniGame function setBaseURI(string calldata baseUri) external override onlyMaintainer { _setBaseURI(baseUri); } /// @inheritdoc IFragmentMiniGame function registerFragmentGroup( string calldata groupName, uint128[] calldata fragmentSupply, bytes32 secretHash, uint128 accountCap ) external override onlyMaintainer whenGroupDoesNotExist(groupName) { // Construct the real group ID bytes16 groupId = groupName.toGroupId(); // Make sure that neither a fragment group nor an object group is registered under the same group id! if (accountCap == 0) revert AccountCapCannotBeZero(); // Make sure that the group secret hash is unique FragmentGroup storage fragmentGroup = _fragmentGroups[groupId]; if (_fragmentGroupIds[secretHash] != bytes16(0)) revert FragmentSecretAlreadyRegistered(); // Associate the secret with the group id _fragmentGroupIds[secretHash] = groupId; // Associate the the group id with the group type _registeredGroups[groupId] = GroupType.Fragment; // Instantiate the fragment groups fragmentGroup.secretHash = secretHash; fragmentGroup.accountCap = accountCap; fragmentGroup.size = uint128(fragmentSupply.length); for (uint128 index = 0; index < fragmentSupply.length; index++) { if (fragmentSupply[index] == 0) revert FragmentSupplyMustBeGreaterThanZero(); fragmentGroup.supply[index] = FragmentMiniGameUtils.toFragmentSupply( fragmentSupply[index], fragmentSupply[index] ); } emit FragmentGroupRegistered(groupId); } /// @inheritdoc IFragmentMiniGame /// @dev Never post the `mintingRequirements` with duplicate tokenIds! That will result in undefined behaviour! function registerObjectGroup(string calldata groupName, MintRequirement[] calldata mintingRequirements) external override onlyMaintainer whenGroupDoesNotExist(groupName) { // Construct the real group ID bytes16 groupId = groupName.toGroupId(); // Associate the the group id with the group type _registeredGroups[groupId] = GroupType.Object; // Instantiate the object group ObjectGroup storage objectGroup = _objectGroups[groupId]; for (uint256 index = 0; index < mintingRequirements.length; index++) { uint256 tokenId = mintingRequirements[index].tokenId; (bytes16 dependantGroupId, uint128 tokenIndex) = parseTokenId(tokenId); // Make sure that the dependant groups token id is valid GroupType gt = _registeredGroups[dependantGroupId]; // Depends on a fragment group. if (gt == GroupType.Fragment) { _checkFragmentGroupExists(dependantGroupId); _fragmentGroups[dependantGroupId].canProvideToken( dependantGroupId, tokenIndex, mintingRequirements[index].necessaryTokenCount ); } // Depends on an object group. else if (gt == GroupType.Object) { if (tokenIndex != 0) revert UnsupportedTokenIndex(dependantGroupId, tokenIndex); _checkObjectGroupExists(dependantGroupId); } // Group type is not supported. else { revert GroupDoesNotExist(dependantGroupId); } bytes32 necessaryNumber = bytes32(uint256(mintingRequirements[index].necessaryTokenCount)); bytes32 tokenIdKey = bytes32(tokenId); objectGroup.mintingRequirements.set(tokenIdKey, necessaryNumber); } emit ObjectGroupRegistered(groupId); } /// @inheritdoc IFragmentMiniGame function deregisterGroup(string calldata groupName) external override onlyMaintainer { // Construct the real group ID bytes16 groupId = groupName.toGroupId(); // Make sure that the dependant groups token id is valid GroupType gt = _registeredGroups[groupId]; // We need to clear up a fragment group. if (gt == GroupType.Fragment) { FragmentGroup storage fg = _fragmentGroups[groupId]; for (uint128 index = 0; index < fg.size; index++) { delete fg.supply[index]; // NOTE: not clearing `fragmentCount` because we don't know the keys! } delete _fragmentGroupIds[fg.secretHash]; delete _fragmentGroups[groupId]; } // We need to clear up an object group else if (gt == GroupType.Object) { delete _objectGroups[groupId]; } else { revert GroupDoesNotExist(groupId); } _registeredGroups[groupId] = GroupType.Unregistered; emit GroupDeregistered(groupId); } /// @inheritdoc IFragmentMiniGame function discover(string calldata fragmentSecret) external override { bytes32 secret = keccak256(abi.encodePacked(fragmentSecret)); // Retrieve the group id from the secret bytes16 groupId = _fragmentGroupIds[secret]; _checkFragmentGroupExists(groupId); FragmentGroup storage fg = _fragmentGroups[groupId]; // Assert that the account can still mint if (fg.fragmentCount[msg.sender] >= fg.accountCap) revert MintingCapReached(msg.sender, groupId, fg.accountCap); // Determine which token index to mint uint256 sourceOfRandomness = uint256( keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp, msg.sender)) ); uint128 index = uint128(sourceOfRandomness % fg.size); for (uint128 i = 0; i < fg.size; i++) { index = (index + 1) % fg.size; // Assert that there's still supply left to be minted. (uint128 supplyLeft, uint128 totalSupply) = fg.supply[index].deconstructFragmentSupply(); if (supplyLeft == 0) continue; // Update the contracts mint state. fg.supply[index] = FragmentMiniGameUtils.toFragmentSupply(supplyLeft - 1, totalSupply); fg.fragmentCount[msg.sender] += 1; // Mint the Fragment NFT. uint256 tokenId = groupId.toFragmentTokenId(index); _mint(msg.sender, tokenId, 1, new bytes(0)); emit FragmentMinted(msg.sender, tokenId); return; // Early return if we have minted the token } // Revert in a case where we cannot mint any token. revert AllItemsDiscovered(groupId); } /// @inheritdoc IFragmentMiniGame function collect(string calldata groupName) external override whenObjectGroupExists(groupName) { bytes16 groupId = groupName.toGroupId(); ObjectGroup storage og = _objectGroups[groupId]; bytes32[] memory childTokenIds = og.mintingRequirements._keys.values(); // iterate over all token ids and check if the user has enough of them for (uint256 index = 0; index < childTokenIds.length; index++) { bytes32 tokenIdKey = childTokenIds[index]; uint256 amountToBurn = uint256(og.mintingRequirements.get(tokenIdKey)); // NOTE: the balance is already checked in the `_burn` function _burn(msg.sender, uint256(tokenIdKey), amountToBurn); } // Mint the object NFT uint256 objectTokenId = groupId.toObjectTokenId(); _mint(msg.sender, objectTokenId, 1, new bytes(0)); emit ObjectMinted(msg.sender, objectTokenId); } /// @inheritdoc IFragmentMiniGame function canCollect(address account, string calldata groupName) external view override whenObjectGroupExists(groupName) returns (bool) { bytes16 groupId = groupName.toGroupId(); // Retrieve the object group ObjectGroup storage og = _objectGroups[groupId]; bytes32[] memory childTokenIds = og.mintingRequirements._keys.values(); // iterate over all token ids and check if the user has enough of them for (uint256 index = 0; index < childTokenIds.length; index++) { bytes32 tokenIdKey = childTokenIds[index]; uint256 amountToBurn = uint256(og.mintingRequirements.get(tokenIdKey)); if (balanceOf(account, uint256(tokenIdKey)) < amountToBurn) return false; } return true; } /// @inheritdoc IFragmentMiniGame function getFragmentGroup(string calldata groupName) external view override whenFragmentGroupExists(groupName) returns ( bytes16 groupId, bytes32 secretHash, uint256[] memory tokenIds, uint128[] memory supplyLeft, uint128[] memory totalSupply ) { // Retrieve the fragment group groupId = groupName.toGroupId(); FragmentGroup storage fg = _fragmentGroups[groupId]; // Populate the response secretHash = fg.secretHash; tokenIds = new uint256[](fg.size); supplyLeft = new uint128[](fg.size); totalSupply = new uint128[](fg.size); for (uint128 index = 0; index < fg.size; index++) { uint256 tokenId = groupId.toFragmentTokenId(index); (uint128 iSupplyLeft, uint128 iTotalSupply) = fg.supply[index].deconstructFragmentSupply(); tokenIds[index] = tokenId; supplyLeft[index] = iSupplyLeft; totalSupply[index] = iTotalSupply; } } /// @inheritdoc IFragmentMiniGame function name() external view override returns (string memory) { return _name; } /// @inheritdoc IFragmentMiniGame function symbol() external view override returns (string memory) { return _symbol; } /// @inheritdoc IFragmentMiniGame function owner() external view override returns (address) { return _getAcl().getRoleMember(Roles.NFT_OWNER, 0); } /// @inheritdoc IFragmentMiniGame function getMintedFragmentsCount(string calldata groupName, address account) external view override whenFragmentGroupExists(groupName) returns (uint256) { // Retrieve the group bytes16 groupId = groupName.toGroupId(); FragmentGroup storage fg = _fragmentGroups[groupId]; // Return the response return fg.fragmentCount[account]; } /// @inheritdoc IFragmentMiniGame function getObjectGroup(string calldata groupName) external view override whenObjectGroupExists(groupName) returns ( bytes16 groupId, uint256 tokenId, MintRequirement[] memory mintingRequirements ) { // Retrieve the group groupId = groupName.toGroupId(); ObjectGroup storage og = _objectGroups[groupId]; // Get all token dependencies bytes32[] memory childTokenIds = og.mintingRequirements._keys.values(); // Populate the response tokenId = groupId.toObjectTokenId(); mintingRequirements = new MintRequirement[](childTokenIds.length); // Iterate over all of the keys (token Ids) and retrieve the necessary token count for (uint256 index = 0; index < childTokenIds.length; index++) { uint128 necessaryTokenCount = uint128(uint256(og.mintingRequirements.get(childTokenIds[index]))); mintingRequirements[index] = MintRequirement({ tokenId: uint256(childTokenIds[index]), necessaryTokenCount: necessaryTokenCount }); } } /// @inheritdoc IFragmentMiniGame function constructTokenId(string calldata groupName, uint128 tokenIndex) external pure override returns (uint256) { return groupName.toGroupId().toFragmentTokenId(tokenIndex); } /// @inheritdoc IFragmentMiniGame function constructGroupId(string calldata groupName) external pure override returns (bytes16) { return groupName.toGroupId(); } /// @inheritdoc IFragmentMiniGame function burn( address from, uint256 tokenId, uint256 amount ) public override(ERC1155BurnableUpgradeable, IFragmentMiniGame) onlyRole(Roles.FRAGMENT_MINI_GAME_BURN) { ERC1155BurnableUpgradeable.burn(from, tokenId, amount); } /// @inheritdoc IFragmentMiniGame function burnBatch( address account, uint256[] memory ids, uint256[] memory values ) public override(ERC1155BurnableUpgradeable, IFragmentMiniGame) onlyRole(Roles.FRAGMENT_MINI_GAME_BURN) { ERC1155BurnableUpgradeable.burnBatch(account, ids, values); } /// @inheritdoc ERC1155Upgradeable function uri(uint256 tokenId) public view override returns (string memory) { return string(abi.encodePacked(super.uri(tokenId), tokenId.toString())); } /// @inheritdoc ERC165Upgradeable function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IFragmentMiniGame).interfaceId || super.supportsInterface(interfaceId); } /// @inheritdoc IFragmentMiniGame function parseTokenId(uint256 tokenId) public pure override returns (bytes16 groupId, uint128 tokenIndex) { // when converting bytes32 to bytes16, the first 16 bytes get saved, the last 16 get dropped groupId = bytes16(bytes32(tokenId)); // when converting uint256 to uint128, the first 16 bytes get dropped, the last 16 get saved tokenIndex = uint128(tokenId); } /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal override onlyAdmin { // solhint-disable-previous-line no-empty-blocks } /// @dev set the base URI and emit an event. function _setBaseURI(string calldata baseUri) internal { _setURI(baseUri); emit UriSet(baseUri); } /// @notice Assert that an group does not exist with a given groupId. /// @param groupId The group ID that we want to query. function _checkGroupDoesNotExist(bytes16 groupId) internal view { if (_registeredGroups[groupId] != GroupType.Unregistered) revert GroupShouldNotExist(groupId); } /// @notice Assert that an fragment group either exists with the provided groupId. /// @param groupId The group ID that we want to query. function _checkFragmentGroupExists(bytes16 groupId) internal view { if (_registeredGroups[groupId] != GroupType.Fragment) revert FragmentGroupShouldExist(groupId); } /// @notice Assert that an object group either exists with the provided groupId. /// @param groupId The group ID that we want to query. function _checkObjectGroupExists(bytes16 groupId) internal view { if (_registeredGroups[groupId] != GroupType.Object) revert ObjectGroupShouldExist(groupId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate that the this implementation remains valid after an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableMap.sol) pragma solidity ^0.8.0; import "./EnumerableSetUpgradeable.sol"; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * The following map types are supported: * * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 * - `bytes32 -> bytes32` (`Bytes32ToBytes32`) since v4.6.0 */ library EnumerableMapUpgradeable { using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set; // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Map type with // bytes32 keys and values. // The Map implementation uses private functions, and user-facing // implementations (such as Uint256ToAddressMap) are just wrappers around // the underlying Map. // This means that we can only create new EnumerableMaps for types that fit // in bytes32. struct Bytes32ToBytes32Map { // Storage of keys EnumerableSetUpgradeable.Bytes32Set _keys; mapping(bytes32 => bytes32) _values; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set( Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value ) internal returns (bool) { map._values[key] = value; return map._keys.add(key); } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { delete map._values[key]; return map._keys.remove(key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { return map._keys.contains(key); } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { return map._keys.length(); } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { bytes32 key = map._keys.at(index); return (key, map._values[key]); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { bytes32 value = map._values[key]; if (value == bytes32(0)) { return (contains(map, key), bytes32(0)); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { bytes32 value = map._values[key]; require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); return value; } /** * @dev Same as {_get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {_tryGet}. */ function get( Bytes32ToBytes32Map storage map, bytes32 key, string memory errorMessage ) internal view returns (bytes32) { bytes32 value = map._values[key]; require(value != 0 || contains(map, key), errorMessage); return value; } // UintToAddressMap struct UintToAddressMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set( UintToAddressMap storage map, uint256 key, address value ) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the set. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. * * _Available since v3.4._ */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key))))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( UintToAddressMap storage map, uint256 key, string memory errorMessage ) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage)))); } // AddressToUintMap struct AddressToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set( AddressToUintMap storage map, address key, uint256 value ) internal returns (bool) { return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(AddressToUintMap storage map, address key) internal returns (bool) { return remove(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(AddressToUintMap storage map, address key) internal view returns (bool) { return contains(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. O(1). */ function length(AddressToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the set. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (address(uint160(uint256(key))), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. * * _Available since v3.4._ */ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(AddressToUintMap storage map, address key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get( AddressToUintMap storage map, address key, string memory errorMessage ) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 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); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/ERC1155.sol) pragma solidity ^0.8.0; import "./IERC1155Upgradeable.sol"; import "./IERC1155ReceiverUpgradeable.sol"; import "./extensions/IERC1155MetadataURIUpgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../utils/introspection/ERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the basic standard multi-token. * See https://eips.ethereum.org/EIPS/eip-1155 * Originally based on code by Enjin: https://github.com/enjin/erc-1155 * * _Available since v3.1._ */ contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155Upgradeable, IERC1155MetadataURIUpgradeable { using AddressUpgradeable for address; // Mapping from token ID to account balances mapping(uint256 => mapping(address => uint256)) private _balances; // Mapping from account to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json string private _uri; /** * @dev See {_setURI}. */ function __ERC1155_init(string memory uri_) internal onlyInitializing { __ERC1155_init_unchained(uri_); } function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing { _setURI(uri_); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { return interfaceId == type(IERC1155Upgradeable).interfaceId || interfaceId == type(IERC1155MetadataURIUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC1155MetadataURI-uri}. * * This implementation returns the same URI for *all* token types. It relies * on the token type ID substitution mechanism * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. * * Clients calling this function must replace the `\{id\}` substring with the * actual token type ID. */ function uri(uint256) public view virtual override returns (string memory) { return _uri; } /** * @dev See {IERC1155-balanceOf}. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { require(account != address(0), "ERC1155: balance query for the zero address"); return _balances[id][account]; } /** * @dev See {IERC1155-balanceOfBatch}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] memory accounts, uint256[] memory ids) public view virtual override returns (uint256[] memory) { require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); uint256[] memory batchBalances = new uint256[](accounts.length); for (uint256 i = 0; i < accounts.length; ++i) { batchBalances[i] = balanceOf(accounts[i], ids[i]); } return batchBalances; } /** * @dev See {IERC1155-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC1155-isApprovedForAll}. */ function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { return _operatorApprovals[account][operator]; } /** * @dev See {IERC1155-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) public virtual override { require( from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: caller is not owner nor approved" ); _safeTransferFrom(from, to, id, amount, data); } /** * @dev See {IERC1155-safeBatchTransferFrom}. */ function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) public virtual override { require( from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: transfer caller is not owner nor approved" ); _safeBatchTransferFrom(from, to, ids, amounts, data); } /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function _safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, from, to, ids, amounts, data); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); unchecked { _balances[id][from] = fromBalance - amount; } _balances[id][to] += amount; emit TransferSingle(operator, from, to, id, amount); _afterTokenTransfer(operator, from, to, ids, amounts, data); _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function _safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); _beforeTokenTransfer(operator, from, to, ids, amounts, data); for (uint256 i = 0; i < ids.length; ++i) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); unchecked { _balances[id][from] = fromBalance - amount; } _balances[id][to] += amount; } emit TransferBatch(operator, from, to, ids, amounts); _afterTokenTransfer(operator, from, to, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); } /** * @dev Sets a new URI for all token types, by relying on the token type ID * substitution mechanism * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. * * By this mechanism, any occurrence of the `\{id\}` substring in either the * URI or any of the amounts in the JSON file at said URI will be replaced by * clients with the token type ID. * * For example, the `https://token-cdn-domain/\{id\}.json` URI would be * interpreted by clients as * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` * for token type ID 0x4cce0. * * See {uri}. * * Because these URIs cannot be meaningfully represented by the {URI} event, * this function emits no events. */ function _setURI(string memory newuri) internal virtual { _uri = newuri; } /** * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); _balances[id][to] += amount; emit TransferSingle(operator, address(0), to, id, amount); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function _mintBatch( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); for (uint256 i = 0; i < ids.length; i++) { _balances[ids[i]][to] += amounts[i]; } emit TransferBatch(operator, address(0), to, ids, amounts); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); } /** * @dev Destroys `amount` tokens of token type `id` from `from` * * Requirements: * * - `from` cannot be the zero address. * - `from` must have at least `amount` tokens of token type `id`. */ function _burn( address from, uint256 id, uint256 amount ) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } emit TransferSingle(operator, from, address(0), id, amount); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. * * Requirements: * * - `ids` and `amounts` must have the same length. */ function _burnBatch( address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); for (uint256 i = 0; i < ids.length; i++) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } } emit TransferBatch(operator, from, address(0), ids, amounts); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits a {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC1155: setting approval status for self"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Hook that is called before any token transfer. This includes minting * and burning, as well as batched variants. * * The same hook is called on both single and batched variants. For single * transfers, the length of the `id` and `amount` arrays will be 1. * * Calling conditions (for each `id` and `amount` pair): * * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens * of token type `id` will be transferred to `to`. * - When `from` is zero, `amount` tokens of token type `id` will be minted * for `to`. * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` * will be burned. * - `from` and `to` are never both zero. * - `ids` and `amounts` have the same, non-zero length. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting * and burning, as well as batched variants. * * The same hook is called on both single and batched variants. For single * transfers, the length of the `id` and `amount` arrays will be 1. * * Calling conditions (for each `id` and `amount` pair): * * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens * of token type `id` will be transferred to `to`. * - When `from` is zero, `amount` tokens of token type `id` will be minted * for `to`. * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` * will be burned. * - `from` and `to` are never both zero. * - `ids` and `amounts` have the same, non-zero length. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} function _doSafeTransferAcceptanceCheck( address operator, address from, address to, uint256 id, uint256 amount, bytes memory data ) private { if (to.isContract()) { try IERC1155ReceiverUpgradeable(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { if (response != IERC1155ReceiverUpgradeable.onERC1155Received.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non ERC1155Receiver implementer"); } } } function _doSafeBatchTransferAcceptanceCheck( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { if (to.isContract()) { try IERC1155ReceiverUpgradeable(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( bytes4 response ) { if (response != IERC1155ReceiverUpgradeable.onERC1155BatchReceived.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non ERC1155Receiver implementer"); } } } function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { uint256[] memory array = new uint256[](1); array[0] = element; return array; } /** * @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[47] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/ERC1155Burnable.sol) pragma solidity ^0.8.0; import "../ERC1155Upgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev Extension of {ERC1155} that allows token holders to destroy both their * own tokens and those that they have been approved to use. * * _Available since v3.1._ */ abstract contract ERC1155BurnableUpgradeable is Initializable, ERC1155Upgradeable { function __ERC1155Burnable_init() internal onlyInitializing { } function __ERC1155Burnable_init_unchained() internal onlyInitializing { } function burn( address account, uint256 id, uint256 value ) public virtual { require( account == _msgSender() || isApprovedForAll(account, _msgSender()), "ERC1155: caller is not owner nor approved" ); _burn(account, id, value); } function burnBatch( address account, uint256[] memory ids, uint256[] memory values ) public virtual { require( account == _msgSender() || isApprovedForAll(account, _msgSender()), "ERC1155: caller is not owner nor approved" ); _burnBatch(account, ids, values); } /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "./IBlockAware.sol"; import "@openzeppelin/contracts/utils/StorageSlot.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /// @notice The implementer contract will always know at which block it was created. abstract contract BlockAware is IBlockAware, Initializable { bytes32 private constant _DEPLOYMENT_BLOCK_NUMBER_SLOT = bytes32(uint256(keccak256("zee-game.block-aware.deployment-block")) - 1); // solhint-disable-next-line func-name-mixedcase function __BlockAware_init() internal onlyInitializing { StorageSlot.getUint256Slot(_DEPLOYMENT_BLOCK_NUMBER_SLOT).value = block.number; } /// @inheritdoc IBlockAware function getDeploymentBlockNumber() external view returns (uint256) { // solhint-disable-previous-line ordering return StorageSlot.getUint256Slot(_DEPLOYMENT_BLOCK_NUMBER_SLOT).value; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; interface IFragmentMiniGame { /// @notice Emitted when a fragment group has been registered. event FragmentGroupRegistered(bytes16 groupId); /// @notice Emitted when an object group has been registered. event ObjectGroupRegistered(bytes16 groupId); /// @notice Emitted when a group has been deregistered. event GroupDeregistered(bytes16 groupId); /// @notice Emitted when the base URI has been set. event UriSet(string newUri); /// @notice Emitted when a fragment group has been minted. event FragmentMinted(address account, uint256 tokenId); /// @notice Emitted when an object group has been minted. event ObjectMinted(address account, uint256 tokenId); /// @notice Thrown when the Object group at a given groupId does not exist. error ObjectGroupShouldExist(bytes16 groupId); /// @notice Thrown when attempting to perform operations on a group that is not registered. error GroupDoesNotExist(bytes16 groupId); /// @notice Thrown when the group at a given groupId exists but it shouldn't. error GroupShouldNotExist(bytes16 groupId); /// @notice Thrown when the Fragment group at a given groupId does not exist. error FragmentGroupShouldExist(bytes16 groupId); /// @notice Thrown when expecting the group to have support for the tokenIndex but it does not support it. error UnsupportedTokenIndex(bytes16 groupId, uint128 tokenIndex); /// @notice Thrown when the max supply cannot be met for a given tokenId. error ImpossibleExpectedSupply(uint256 tokenId, uint256 necessarySupply); /// @notice Thrown when the fragment secret is already used for another fragment group. error FragmentSecretAlreadyRegistered(); /// @notice Thrown when the supply of a fragment is larger than 0. error FragmentSupplyMustBeGreaterThanZero(); /// @notice Thrown when the fragment groups account cap is specified at 0. error AccountCapCannotBeZero(); /// @notice Thrown when all fragments have been already minted. error AllItemsDiscovered(bytes16 groupId); /// @notice Thrown when a user has minted the allowed amount of fragments in his a group. error MintingCapReached(address account, bytes16 groupId, uint256 accountCap); /// @notice Mint requirements are defined for object groups, they define the dependant /// tokenIds and their corresponding amounts to be able to mint a given object NFT. struct MintRequirement { uint256 tokenId; // key uint128 necessaryTokenCount; // value } /// @notice Register a new Fragment group that can be discovered with a secret phrase. /// @param groupName A unique name for the group. /// @param fragmentSupply The amount of fragments that can be minted. The index of the item determines the token ID. /// @param secretHash The keccak256 hash of the secret that is used to discover the fragments. /// @param accountCap The maximum amount of fragments that can be minted by a single account. function registerFragmentGroup( string calldata groupName, uint128[] calldata fragmentSupply, bytes32 secretHash, uint128 accountCap ) external; /// @notice Register a new Object group that can created by owning all of the required tokenIds. /// @param groupName A unique name for the group. /// @param mintingRequirements The minting requirements for the group. function registerObjectGroup(string calldata groupName, MintRequirement[] calldata mintingRequirements) external; /// @notice Deregister a group. /// @param groupName The name of the group that already has been registered. function deregisterGroup(string calldata groupName) external; /// @notice Try to mint a new fragment NFT by providing a secret. /// @param fragmentSecret The secret phrase that is used to discover the fragments. function discover(string calldata fragmentSecret) external; /// @notice Combine all of the necessary fragments or subgroup NFTs to create an object NFT. /// @param groupName The name of the group for which we need to check the requirements and attempt to mint. function collect(string calldata groupName) external; /// @notice Set the base URI for the tokens. /// @param baseURI The base URI for the tokens. function setBaseURI(string calldata baseURI) external; /// @notice Get the name of the contract /// @return The name of the contract. function name() external view returns (string memory); /// @notice Get the symbol of the contract /// @return The symbol of the contract. function symbol() external view returns (string memory); /// @notice Get the owner of the contract. /// @return The owner of the contract. function owner() external view returns (address); /// @notice Check if the given account is able to mint the given object group. /// @param account The account that is trying to mint the object group. /// @param groupName The name of the group that is being minted. /// @return True if the NFT can be minted. function canCollect(address account, string calldata groupName) external view returns (bool); /// @notice Burn an arbitrary token. /// @param from Address of the account for which we want to burn the tokens. /// @param tokenId The tokenId of the token to burn. /// @param amount The amount of tokens that we want to burn. function burn( address from, uint256 tokenId, uint256 amount ) external; /// @notice Burn multiples of arbitrary tokens. /// @param account Address of the account for which we want to burn the tokens. /// @param ids The tokenIds of the tokens to burn. /// @param values The amounts of tokens that we want to burn, index corresponds to `ids`. function burnBatch( address account, uint256[] calldata ids, uint256[] calldata values ) external; /// @notice Retrieve information about a fragment group /// @param groupName The name of the group that we want to query. /// @return groupId The unique group identifier. /// @return secretHash The hash of the secret used for discovering items fom the group. /// @return tokenIds The tokenIds of the fragments in the group. /// @return supplyLeft The amount of fragments left to mint, index corresponds to `tokenIds`. /// @return totalSupply The total amount of fragments that can be minted, index corresponds to `tokenIds`. function getFragmentGroup(string calldata groupName) external view returns ( bytes16 groupId, bytes32 secretHash, uint256[] memory tokenIds, uint128[] memory supplyLeft, uint128[] memory totalSupply ); /// @notice Get the number of minted fragments for a given user account. /// @param groupName The name of the group that we want to query. /// @param account The address of the account for which we want to query the number of minted fragments. /// @return number The number of minted fragments for the given user account. function getMintedFragmentsCount(string calldata groupName, address account) external view returns (uint256); /// @notice Retrieve information about an Object group. /// @param groupName The name of the group that we want to query. /// @return groupId The unique group identifier. /// @return tokenId The tokenId that can be minted by the object group. /// @return mintingRequirements The minting requirements for the object group. function getObjectGroup(string calldata groupName) external view returns ( bytes16 groupId, uint256 tokenId, MintRequirement[] calldata mintingRequirements ); /// @notice construct the token id for a given group. /// @param groupName The name of the group that we want to query. /// @param tokenIndex The index of the token in the group. /// @return tokenId The tokenId of the token at the given index for the group. /// @dev if the group refers to an object group, the tokenIndex is `0`. function constructTokenId(string calldata groupName, uint128 tokenIndex) external pure returns (uint256); /// @notice construct the group id for a given group. /// @param groupName The name of the group that we want to query. /// @return groupId The groupId of the group. function constructGroupId(string calldata groupName) external pure returns (bytes16); /// @notice Deconstruct a token id into its sub-components. /// @param tokenId The tokenId that we want to deconstruct. /// @return groupId The groupId of the group retrieved from the tokenId. /// @return tokenIndex The index of the token retrieved from the tokenId. function parseTokenId(uint256 tokenId) external pure returns (bytes16 groupId, uint128 tokenIndex); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableMapUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; abstract contract FragmentMiniGameStorage { using EnumerableMapUpgradeable for EnumerableMapUpgradeable.Bytes32ToBytes32Map; /// @dev represents a group of fragments struct FragmentGroup { bytes32 secretHash; uint128 accountCap; uint128 size; // Token Index => bytes32(uint128(supplyLeft), uint128(totalSupply)) mapping(uint128 => bytes32) supply; // Account => already minted number of tokens mapping(address => uint256) fragmentCount; } /// @dev represents a single object group NFT struct ObjectGroup { // TokenID => amount of items needed to mint EnumerableMapUpgradeable.Bytes32ToBytes32Map mintingRequirements; } /// @dev represents the possible type of a group. enum GroupType { Unregistered, Fragment, Object } // Contract name string internal _name; // Contract symbol string internal _symbol; // Secret hash to group id (only for fragment groups) mapping(bytes32 => bytes16) internal _fragmentGroupIds; // Group id to fragment group mapping(bytes16 => FragmentGroup) internal _fragmentGroups; // Group id to object group mapping(bytes16 => ObjectGroup) internal _objectGroups; // Group id to group type mapping(bytes16 => GroupType) internal _registeredGroups; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "./IFragmentMiniGame.sol"; import "./FragmentMiniGameStorage.sol"; library FragmentMiniGameUtils { /// @dev Make sure that the given fragment group can provide the token at the desired token index. function canProvideToken( FragmentMiniGameStorage.FragmentGroup storage fg, bytes16 groupId, uint128 desiredTokenIndex, uint128 necessaryTokenCount ) internal view { (, uint128 totalSupply) = deconstructFragmentSupply(fg.supply[desiredTokenIndex]); // We're checking a case where the expected token desiredTokenIndex is not supported by the fragment group. if (fg.size <= desiredTokenIndex) revert IFragmentMiniGame.UnsupportedTokenIndex(groupId, desiredTokenIndex); if (totalSupply < necessaryTokenCount) revert IFragmentMiniGame.ImpossibleExpectedSupply( toFragmentTokenId(groupId, desiredTokenIndex), necessaryTokenCount ); } function toGroupId(string memory group) internal pure returns (bytes16) { return bytes16(keccak256(bytes(group))); } function toFragmentTokenId(bytes16 groupId, uint128 tokenIndex) internal pure returns (uint256 tokenId) { return _constructTokenId(groupId, tokenIndex); } /// @dev Object groups will always use the index `0` function toObjectTokenId(bytes16 groupId) internal pure returns (uint256 tokenId) { return _constructTokenId(groupId, 0); } function toFragmentSupply(uint128 supplyLeft, uint128 totalSupply) internal pure returns (bytes32) { return bytes32((uint256(supplyLeft) << 128) + uint256(totalSupply)); } function deconstructFragmentSupply(bytes32 fragmentSupply) internal pure returns (uint128 supplyLeft, uint128 totalSupply) { supplyLeft = uint128(uint256(fragmentSupply) >> 128); totalSupply = uint128(uint256(fragmentSupply)); } function _constructTokenId(bytes16 groupId, uint128 tokenIndex) private pure returns (uint256 tokenId) { // when converting bytes16 to bytes32, the bytes get padded with zeros on the right side. tokenId += uint256(bytes32(groupId)); // when converting uint128 to uint256, the number gets padded with zeros on the left side. tokenId += uint256(tokenIndex); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967UpgradeUpgradeable is Initializable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { _functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @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) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.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 IERC1155Upgradeable is IERC165Upgradeable { /** * @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 be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155ReceiverUpgradeable is IERC165Upgradeable { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol) pragma solidity ^0.8.0; import "../IERC1155Upgradeable.sol"; /** * @dev Interface of the optional ERC1155MetadataExtension interface, as defined * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. * * _Available since v3.1._ */ interface IERC1155MetadataURIUpgradeable is IERC1155Upgradeable { /** * @dev Returns the URI for token type `id`. * * If the `\{id\}` substring is present in the URI, it must be replaced by * clients with the actual token type ID. */ function uri(uint256 id) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; /// @notice The implementer contract will always know at which block it was created. interface IBlockAware { /// @notice Get deployment block number. function getDeploymentBlockNumber() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "../mini-game/FragmentMiniGame.sol"; /// @notice mock FragmentMiniGame implementation for testing purposes contract TestFragmentMiniGameV2 is FragmentMiniGame { // solhint-disable-next-line comprehensive-interface function version() external pure returns (string memory) { return "V2"; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlEnumerableUpgradeable.sol"; import "./AccessControlUpgradeable.sol"; import "../utils/structs/EnumerableSetUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable { function __AccessControlEnumerable_init() internal onlyInitializing { } function __AccessControlEnumerable_init_unchained() internal onlyInitializing { } using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _roleMembers; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerableUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev 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) public view virtual override returns (address) { return _roleMembers[role].at(index); } /** * @dev 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) public view virtual override returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override { super._grantRole(role, account); _roleMembers[role].add(account); } /** * @dev Overload {_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override { super._revokeRole(role, account); _roleMembers[role].remove(account); } /** * @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[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(uint160(account), 20), " is missing role ", StringsUpgradeable.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } /** * @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[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "../acl/IACL.sol"; import "../mini-game/IFragmentMiniGame.sol"; contract InterfacePrinter { function acl() external pure returns (bytes4) { // solhint-disable-previous-line comprehensive-interface return bytes4(type(IACL).interfaceId); } function fragmentMiniGame() external pure returns (bytes4) { // solhint-disable-previous-line comprehensive-interface return bytes4(type(IFragmentMiniGame).interfaceId); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "./IACL.sol"; import "./Roles.sol"; import "../common/BlockAware.sol"; /// @title Access Control List contract contract ACL is IACL, AccessControlEnumerableUpgradeable, UUPSUpgradeable, BlockAware { /// @dev Constructor that gets called for the implementation contract. constructor() initializer { if (Roles.ADMIN != DEFAULT_ADMIN_ROLE) revert RolesContractIncorrectlyConfigured(); } function initialize(address admin) external initializer { // solhint-disable-previous-line comprehensive-interface __UUPSUpgradeable_init(); __AccessControlEnumerable_init(); __BlockAware_init(); // Set up roles _grantRole(Roles.ADMIN, admin); } /// @inheritdoc IACL function checkRole(bytes32 role, address account) external view override { _checkRole(role, account); } /// @inheritdoc IACL function getAdminRole() external pure override returns (bytes32) { return Roles.ADMIN; } /// @inheritdoc IACL function getMaintainerRole() external pure override returns (bytes32) { return Roles.MAINTAINER; } /// @inheritdoc AccessControlEnumerableUpgradeable function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { // Explicitly declare which super-class to use return interfaceId == type(IACL).interfaceId || super.supportsInterface(interfaceId); } /// @inheritdoc AccessControlEnumerableUpgradeable function _grantRole(bytes32 role, address account) internal virtual override { if (role == Roles.NFT_OWNER && getRoleMemberCount(role) > 0) revert CannotHaveMoreThanOneAddressInRole(); super._grantRole(role, account); } /// @inheritdoc AccessControlEnumerableUpgradeable function _revokeRole(bytes32 role, address account) internal virtual override { if (role == Roles.ADMIN && getRoleMemberCount(role) == 1) revert CannotRemoveLastAdmin(); super._revokeRole(role, account); } /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal override onlyRole(DEFAULT_ADMIN_ROLE) { // solhint-disable-previous-line no-empty-blocks } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "../acl/ACL.sol"; /// @notice mock ACL implementation for testing purposes contract TestACLV2 is ACL { // solhint-disable-next-line comprehensive-interface function version() external pure returns (string memory) { return "V2"; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "erc721a-upgradeable/contracts/extensions/ERC721AQueryableUpgradeable.sol"; import "erc721a-upgradeable/contracts/extensions/ERC721ABurnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "../acl/access-controlled/AccessControlledUpgradeable.sol"; import "../common/BlockAware.sol"; import "./IZeeNFT.sol"; contract ZeeNFT is IZeeNFT, UUPSUpgradeable, ERC721ABurnableUpgradeable, ERC721AQueryableUpgradeable, AccessControlledUpgradeable, BlockAware { /// @dev Constructor that gets called for the implementation contract. constructor() initializerERC721A { // solhint-disable-previous-line no-empty-blocks } // solhint-disable-next-line comprehensive-interface function initialize(address acl) external initializer initializerERC721A { __ERC721A_init("Zee NFT", "Zee"); __BlockAware_init(); __ERC721ABurnable_init(); __ERC721AQueryable_init(); __AccessControlled_init(acl); } function mint(address receiver, uint256 quantity) external override onlyRole(Roles.ZEE_NFT_MINT) { _safeMint(receiver, quantity); } function burn(uint256 tokenId) public override(ERC721ABurnableUpgradeable, IZeeNFT) onlyRole(Roles.ZEE_NFT_BURN) { _burn(tokenId); } /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal override onlyAdmin { // solhint-disable-previous-line no-empty-blocks } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.0.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import './IERC721AQueryableUpgradeable.sol'; import '../ERC721AUpgradeable.sol'; import '../ERC721A__Initializable.sol'; /** * @title ERC721A Queryable * @dev ERC721A subclass with convenience query functions. */ abstract contract ERC721AQueryableUpgradeable is ERC721A__Initializable, ERC721AUpgradeable, IERC721AQueryableUpgradeable { function __ERC721AQueryable_init() internal onlyInitializingERC721A { __ERC721AQueryable_init_unchained(); } function __ERC721AQueryable_init_unchained() internal onlyInitializingERC721A {} /** * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. * * If the `tokenId` is out of bounds: * - `addr` = `address(0)` * - `startTimestamp` = `0` * - `burned` = `false` * * If the `tokenId` is burned: * - `addr` = `<Address of owner before token was burned>` * - `startTimestamp` = `<Timestamp when token was burned>` * - `burned = `true` * * Otherwise: * - `addr` = `<Address of owner>` * - `startTimestamp` = `<Timestamp of start of ownership>` * - `burned = `false` */ function explicitOwnershipOf(uint256 tokenId) public view override returns (TokenOwnership memory) { TokenOwnership memory ownership; if (tokenId < _startTokenId() || tokenId >= _nextTokenId()) { return ownership; } ownership = _ownershipAt(tokenId); if (ownership.burned) { return ownership; } return _ownershipOf(tokenId); } /** * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. * See {ERC721AQueryable-explicitOwnershipOf} */ function explicitOwnershipsOf(uint256[] memory tokenIds) external view override returns (TokenOwnership[] memory) { unchecked { uint256 tokenIdsLength = tokenIds.length; TokenOwnership[] memory ownerships = new TokenOwnership[](tokenIdsLength); for (uint256 i; i != tokenIdsLength; ++i) { ownerships[i] = explicitOwnershipOf(tokenIds[i]); } return ownerships; } } /** * @dev Returns an array of token IDs owned by `owner`, * in the range [`start`, `stop`) * (i.e. `start <= tokenId < stop`). * * This function allows for tokens to be queried if the collection * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. * * Requirements: * * - `start` < `stop` */ function tokensOfOwnerIn( address owner, uint256 start, uint256 stop ) external view override returns (uint256[] memory) { unchecked { if (start >= stop) revert InvalidQueryRange(); uint256 tokenIdsIdx; uint256 stopLimit = _nextTokenId(); // Set `start = max(start, _startTokenId())`. if (start < _startTokenId()) { start = _startTokenId(); } // Set `stop = min(stop, stopLimit)`. if (stop > stopLimit) { stop = stopLimit; } uint256 tokenIdsMaxLength = balanceOf(owner); // Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`, // to cater for cases where `balanceOf(owner)` is too big. if (start < stop) { uint256 rangeLength = stop - start; if (rangeLength < tokenIdsMaxLength) { tokenIdsMaxLength = rangeLength; } } else { tokenIdsMaxLength = 0; } uint256[] memory tokenIds = new uint256[](tokenIdsMaxLength); if (tokenIdsMaxLength == 0) { return tokenIds; } // We need to call `explicitOwnershipOf(start)`, // because the slot at `start` may not be initialized. TokenOwnership memory ownership = explicitOwnershipOf(start); address currOwnershipAddr; // If the starting slot exists (i.e. not burned), initialize `currOwnershipAddr`. // `ownership.address` will not be zero, as `start` is clamped to the valid token ID range. if (!ownership.burned) { currOwnershipAddr = ownership.addr; } for (uint256 i = start; i != stop && tokenIdsIdx != tokenIdsMaxLength; ++i) { ownership = _ownershipAt(i); if (ownership.burned) { continue; } if (ownership.addr != address(0)) { currOwnershipAddr = ownership.addr; } if (currOwnershipAddr == owner) { tokenIds[tokenIdsIdx++] = i; } } // Downsize the array to fit. assembly { mstore(tokenIds, tokenIdsIdx) } return tokenIds; } } /** * @dev Returns an array of token IDs owned by `owner`. * * This function scans the ownership mapping and is O(totalSupply) in complexity. * It is meant to be called off-chain. * * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into * multiple smaller scans if the collection is large enough to cause * an out-of-gas error (10K pfp collections should be fine). */ function tokensOfOwner(address owner) external view override returns (uint256[] memory) { unchecked { uint256 tokenIdsIdx; address currOwnershipAddr; uint256 tokenIdsLength = balanceOf(owner); uint256[] memory tokenIds = new uint256[](tokenIdsLength); TokenOwnership memory ownership; for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) { ownership = _ownershipAt(i); if (ownership.burned) { continue; } if (ownership.addr != address(0)) { currOwnershipAddr = ownership.addr; } if (currOwnershipAddr == owner) { tokenIds[tokenIdsIdx++] = i; } } return tokenIds; } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.0.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import './IERC721ABurnableUpgradeable.sol'; import '../ERC721AUpgradeable.sol'; import '../ERC721A__Initializable.sol'; /** * @title ERC721A Burnable Token * @dev ERC721A Token that can be irreversibly burned (destroyed). */ abstract contract ERC721ABurnableUpgradeable is ERC721A__Initializable, ERC721AUpgradeable, IERC721ABurnableUpgradeable { function __ERC721ABurnable_init() internal onlyInitializingERC721A { __ERC721ABurnable_init_unchained(); } function __ERC721ABurnable_init_unchained() internal onlyInitializingERC721A {} /** * @dev Burns `tokenId`. See {ERC721A-_burn}. * * Requirements: * * - The caller must own `tokenId` or be an approved operator. */ function burn(uint256 tokenId) public virtual override { _burn(tokenId, true); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol) pragma solidity ^0.8.0; import "./AddressUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract MulticallUpgradeable is Initializable { function __Multicall_init() internal onlyInitializing { } function __Multicall_init_unchained() internal onlyInitializing { } /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = _functionDelegateCall(address(this), data[i]); } return results; } /** * @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) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @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[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; interface IZeeNFT { /// @notice Mint specific amount of tokens for a user. function mint(address receiver, uint256 quantity) external; /// @notice Burn a specific token ID. function burn(uint256 tokenId) external; }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.0.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721AUpgradeable.sol'; /** * @dev Interface of an ERC721AQueryable compliant contract. */ interface IERC721AQueryableUpgradeable is IERC721AUpgradeable { /** * Invalid query range (`start` >= `stop`). */ error InvalidQueryRange(); /** * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting. * * If the `tokenId` is out of bounds: * - `addr` = `address(0)` * - `startTimestamp` = `0` * - `burned` = `false` * * If the `tokenId` is burned: * - `addr` = `<Address of owner before token was burned>` * - `startTimestamp` = `<Timestamp when token was burned>` * - `burned = `true` * * Otherwise: * - `addr` = `<Address of owner>` * - `startTimestamp` = `<Timestamp of start of ownership>` * - `burned = `false` */ function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory); /** * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order. * See {ERC721AQueryable-explicitOwnershipOf} */ function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory); /** * @dev Returns an array of token IDs owned by `owner`, * in the range [`start`, `stop`) * (i.e. `start <= tokenId < stop`). * * This function allows for tokens to be queried if the collection * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}. * * Requirements: * * - `start` < `stop` */ function tokensOfOwnerIn( address owner, uint256 start, uint256 stop ) external view returns (uint256[] memory); /** * @dev Returns an array of token IDs owned by `owner`. * * This function scans the ownership mapping and is O(totalSupply) in complexity. * It is meant to be called off-chain. * * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into * multiple smaller scans if the collection is large enough to cause * an out-of-gas error (10K pfp collections should be fine). */ function tokensOfOwner(address owner) external view returns (uint256[] memory); }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.0.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import './IERC721AUpgradeable.sol'; import {ERC721AStorage} from './ERC721AStorage.sol'; import './ERC721A__Initializable.sol'; /** * @dev ERC721 token receiver interface. */ interface ERC721A__IERC721ReceiverUpgradeable { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension. Built to optimize for lower gas during batch mints. * * Assumes serials are sequentially minted starting at _startTokenId() (defaults to 0, e.g. 0, 1, 2, 3..). * * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. * * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). */ contract ERC721AUpgradeable is ERC721A__Initializable, IERC721AUpgradeable { using ERC721AStorage for ERC721AStorage.Layout; // Mask of an entry in packed address data. uint256 private constant BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; // The bit position of `numberMinted` in packed address data. uint256 private constant BITPOS_NUMBER_MINTED = 64; // The bit position of `numberBurned` in packed address data. uint256 private constant BITPOS_NUMBER_BURNED = 128; // The bit position of `aux` in packed address data. uint256 private constant BITPOS_AUX = 192; // Mask of all 256 bits in packed address data except the 64 bits for `aux`. uint256 private constant BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; // The bit position of `startTimestamp` in packed ownership. uint256 private constant BITPOS_START_TIMESTAMP = 160; // The bit mask of the `burned` bit in packed ownership. uint256 private constant BITMASK_BURNED = 1 << 224; // The bit position of the `nextInitialized` bit in packed ownership. uint256 private constant BITPOS_NEXT_INITIALIZED = 225; // The bit mask of the `nextInitialized` bit in packed ownership. uint256 private constant BITMASK_NEXT_INITIALIZED = 1 << 225; function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializingERC721A { __ERC721A_init_unchained(name_, symbol_); } function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializingERC721A { ERC721AStorage.layout()._name = name_; ERC721AStorage.layout()._symbol = symbol_; ERC721AStorage.layout()._currentIndex = _startTokenId(); } /** * @dev Returns the starting token ID. * To change the starting token ID, please override this function. */ function _startTokenId() internal view virtual returns (uint256) { return 0; } /** * @dev Returns the next token ID to be minted. */ function _nextTokenId() internal view returns (uint256) { return ERC721AStorage.layout()._currentIndex; } /** * @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 override 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(); } } /** * @dev Returns the total amount of tokens minted in the contract. */ function _totalMinted() internal view 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 returns (uint256) { return ERC721AStorage.layout()._burnCounter; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { // The interface IDs are constants representing the first 4 bytes of the XOR of // all function selectors in the interface. See: https://eips.ethereum.org/EIPS/eip-165 // e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)` return interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view override returns (uint256) { if (_addressToUint256(owner) == 0) revert BalanceQueryForZeroAddress(); return ERC721AStorage.layout()._packedAddressData[owner] & BITMASK_ADDRESS_DATA_ENTRY; } /** * 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 auxillary 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 auxillary 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 { uint256 packed = ERC721AStorage.layout()._packedAddressData[owner]; uint256 auxCasted; assembly { // Cast aux without masking. auxCasted := aux } packed = (packed & BITMASK_AUX_COMPLEMENT) | (auxCasted << BITPOS_AUX); ERC721AStorage.layout()._packedAddressData[owner] = packed; } /** * Returns the packed ownership data of `tokenId`. */ function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { uint256 curr = tokenId; unchecked { if (_startTokenId() <= curr) if (curr < ERC721AStorage.layout()._currentIndex) { uint256 packed = ERC721AStorage.layout()._packedOwnerships[curr]; // If not burned. if (packed & BITMASK_BURNED == 0) { // Invariant: // There will always be an ownership that has an address and is not burned // before an ownership that does not have an address and is not burned. // Hence, curr will not underflow. // // We can directly compare the packed value. // If the address is zero, packed is zero. while (packed == 0) { packed = ERC721AStorage.layout()._packedOwnerships[--curr]; } return packed; } } } revert OwnerQueryForNonexistentToken(); } /** * Returns the unpacked `TokenOwnership` struct from `packed`. */ function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { ownership.addr = address(uint160(packed)); ownership.startTimestamp = uint64(packed >> BITPOS_START_TIMESTAMP); ownership.burned = packed & BITMASK_BURNED != 0; } /** * Returns the unpacked `TokenOwnership` struct at `index`. */ function _ownershipAt(uint256 index) internal view returns (TokenOwnership memory) { return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]); } /** * @dev Initializes the ownership slot minted at `index` for efficiency purposes. */ function _initializeOwnershipAt(uint256 index) internal { if (ERC721AStorage.layout()._packedOwnerships[index] == 0) { ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index); } } /** * Gas spent here starts off proportional to the maximum mint batch size. * It gradually moves to O(1) as tokens get transferred around in the collection over time. */ function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnershipOf(tokenId)); } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view override returns (address) { return address(uint160(_packedOwnershipOf(tokenId))); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return ERC721AStorage.layout()._name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return ERC721AStorage.layout()._symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); string memory baseURI = _baseURI(); return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; } /** * @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, can be overriden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ''; } /** * @dev Casts the address to uint256 without masking. */ function _addressToUint256(address value) private pure returns (uint256 result) { assembly { result := value } } /** * @dev Casts the boolean to uint256 without branching. */ function _boolToUint256(bool value) private pure returns (uint256 result) { assembly { result := value } } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public override { address owner = address(uint160(_packedOwnershipOf(tokenId))); if (to == owner) revert ApprovalToCurrentOwner(); if (_msgSenderERC721A() != owner) if (!isApprovedForAll(owner, _msgSenderERC721A())) { revert ApprovalCallerNotOwnerNorApproved(); } ERC721AStorage.layout()._tokenApprovals[tokenId] = to; emit Approval(owner, to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view override returns (address) { if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); return ERC721AStorage.layout()._tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { if (operator == _msgSenderERC721A()) revert ApproveToCaller(); ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved; emit ApprovalForAll(_msgSenderERC721A(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return ERC721AStorage.layout()._operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ''); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { _transfer(from, to, tokenId); if (to.code.length != 0) if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { revert TransferToNonERC721ReceiverImplementer(); } } /** * @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 (`_mint`), */ function _exists(uint256 tokenId) internal view returns (bool) { return _startTokenId() <= tokenId && tokenId < ERC721AStorage.layout()._currentIndex && // If within bounds, ERC721AStorage.layout()._packedOwnerships[tokenId] & BITMASK_BURNED == 0; // and not burned. } /** * @dev Equivalent to `_safeMint(to, quantity, '')`. */ function _safeMint(address to, uint256 quantity) internal { _safeMint(to, 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. * * Emits a {Transfer} event. */ function _safeMint( address to, uint256 quantity, bytes memory _data ) internal { uint256 startTokenId = ERC721AStorage.layout()._currentIndex; if (_addressToUint256(to) == 0) revert MintToZeroAddress(); if (quantity == 0) revert MintZeroQuantity(); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are incredibly unrealistic. // balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1 // updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1 unchecked { // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the balance and number minted. 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] = _addressToUint256(to) | (block.timestamp << BITPOS_START_TIMESTAMP) | (_boolToUint256(quantity == 1) << BITPOS_NEXT_INITIALIZED); uint256 updatedIndex = startTokenId; uint256 end = updatedIndex + quantity; if (to.code.length != 0) { do { emit Transfer(address(0), to, updatedIndex); if (!_checkContractOnERC721Received(address(0), to, updatedIndex++, _data)) { revert TransferToNonERC721ReceiverImplementer(); } } while (updatedIndex < end); // Reentrancy protection if (ERC721AStorage.layout()._currentIndex != startTokenId) revert(); } else { do { emit Transfer(address(0), to, updatedIndex++); } while (updatedIndex < end); } ERC721AStorage.layout()._currentIndex = updatedIndex; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @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. */ function _mint(address to, uint256 quantity) internal { uint256 startTokenId = ERC721AStorage.layout()._currentIndex; if (_addressToUint256(to) == 0) revert MintToZeroAddress(); if (quantity == 0) revert MintZeroQuantity(); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are incredibly unrealistic. // balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1 // updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1 unchecked { // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the balance and number minted. 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] = _addressToUint256(to) | (block.timestamp << BITPOS_START_TIMESTAMP) | (_boolToUint256(quantity == 1) << BITPOS_NEXT_INITIALIZED); uint256 updatedIndex = startTokenId; uint256 end = updatedIndex + quantity; do { emit Transfer(address(0), to, updatedIndex++); } while (updatedIndex < end); ERC721AStorage.layout()._currentIndex = updatedIndex; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Transfers `tokenId` from `from` to `to`. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) private { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); address approvedAddress = ERC721AStorage.layout()._tokenApprovals[tokenId]; bool isApprovedOrOwner = (_msgSenderERC721A() == from || isApprovedForAll(from, _msgSenderERC721A()) || approvedAddress == _msgSenderERC721A()); if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved(); if (_addressToUint256(to) == 0) revert TransferToZeroAddress(); _beforeTokenTransfers(from, to, tokenId, 1); // Clear approvals from the previous owner. if (_addressToUint256(approvedAddress) != 0) { delete ERC721AStorage.layout()._tokenApprovals[tokenId]; } // 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] = _addressToUint256(to) | (block.timestamp << BITPOS_START_TIMESTAMP) | BITMASK_NEXT_INITIALIZED; // 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, to, tokenId); _afterTokenTransfers(from, to, tokenId, 1); } /** * @dev Equivalent to `_burn(tokenId, false)`. */ function _burn(uint256 tokenId) internal virtual { _burn(tokenId, false); } /** * @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)); address approvedAddress = ERC721AStorage.layout()._tokenApprovals[tokenId]; if (approvalCheck) { bool isApprovedOrOwner = (_msgSenderERC721A() == from || isApprovedForAll(from, _msgSenderERC721A()) || approvedAddress == _msgSenderERC721A()); if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved(); } _beforeTokenTransfers(from, address(0), tokenId, 1); // Clear approvals from the previous owner. if (_addressToUint256(approvedAddress) != 0) { delete ERC721AStorage.layout()._tokenApprovals[tokenId]; } // 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] = _addressToUint256(from) | (block.timestamp << BITPOS_START_TIMESTAMP) | BITMASK_BURNED | BITMASK_NEXT_INITIALIZED; // 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++; } } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkContractOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private 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(); } else { assembly { revert(add(32, reason), mload(reason)) } } } } /** * @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 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 returns (string memory ptr) { assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), // but we allocate 128 bytes to keep the free memory pointer 32-byte word aliged. // We will need 1 32-byte word to store the length, // and 3 32-byte words to store a maximum of 78 digits. Total: 32 + 3 * 32 = 128. ptr := add(mload(0x40), 128) // Update the free memory pointer to allocate. mstore(0x40, ptr) // Cache the end of the memory to calculate the length later. let end := ptr // We write the string from the rightmost digit to the leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // Costs a bit more than early returning for the zero case, // but cheaper in terms of deployment and overall runtime costs. for { // Initialize and perform the first pass without check. let temp := value // Move the pointer 1 byte leftwards to point to an empty character slot. ptr := sub(ptr, 1) // Write the character to the pointer. 48 is the ASCII index of '0'. mstore8(ptr, add(48, mod(temp, 10))) temp := div(temp, 10) } temp { // Keep dividing `temp` until zero. temp := div(temp, 10) } { // Body of the for loop. ptr := sub(ptr, 1) mstore8(ptr, add(48, mod(temp, 10))) } let length := sub(end, ptr) // Move the pointer 32 bytes leftwards to make room for the length. ptr := sub(ptr, 32) // Store the length. mstore(ptr, length) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable diamond facet 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. * * 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. */ import {ERC721A__InitializableStorage} from './ERC721A__InitializableStorage.sol'; abstract contract ERC721A__Initializable { using ERC721A__InitializableStorage for ERC721A__InitializableStorage.Layout; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializerERC721A() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require( ERC721A__InitializableStorage.layout()._initializing ? _isConstructor() : !ERC721A__InitializableStorage.layout()._initialized, 'ERC721A__Initializable: contract is already initialized' ); bool isTopLevelCall = !ERC721A__InitializableStorage.layout()._initializing; if (isTopLevelCall) { ERC721A__InitializableStorage.layout()._initializing = true; ERC721A__InitializableStorage.layout()._initialized = true; } _; if (isTopLevelCall) { ERC721A__InitializableStorage.layout()._initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializingERC721A() { require( ERC721A__InitializableStorage.layout()._initializing, 'ERC721A__Initializable: contract is not initializing' ); _; } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.0.0 // Creator: Chiru Labs pragma solidity ^0.8.4; /** * @dev Interface of an ERC721A compliant contract. */ interface IERC721AUpgradeable { /** * The caller must own the token or be an approved operator. */ error ApprovalCallerNotOwnerNorApproved(); /** * The token does not exist. */ error ApprovalQueryForNonexistentToken(); /** * The caller cannot approve to their own address. */ error ApproveToCaller(); /** * The caller cannot approve to the current owner. */ error ApprovalToCurrentOwner(); /** * 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(); struct TokenOwnership { // The address of the owner. address addr; // Keeps track of the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; } /** * @dev Returns the total amount of tokens stored by the contract. * * Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens. */ function totalSupply() external view returns (uint256); // ============================== // 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); // ============================== // IERC721 // ============================== /** * @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 be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * 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); // ============================== // IERC721Metadata // ============================== /** * @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: MIT pragma solidity ^0.8.0; import {ERC721AUpgradeable} from './ERC721AUpgradeable.sol'; library ERC721AStorage { struct Layout { // The tokenId of the next token 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` 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 => address) _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 pragma solidity ^0.8.0; /** * @dev This is a base storage for the initialization function for upgradeable diamond facet contracts **/ library ERC721A__InitializableStorage { struct Layout { /* * Indicates that the contract has been initialized. */ bool _initialized; /* * Indicates that the contract is in the process of being initialized. */ bool _initializing; } bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.initializable.facet'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.0.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721AUpgradeable.sol'; /** * @dev Interface of an ERC721ABurnable compliant contract. */ interface IERC721ABurnableUpgradeable is IERC721AUpgradeable { /** * @dev Burns `tokenId`. See {ERC721A-_burn}. * * Requirements: * * - The caller must own `tokenId` or be an approved operator. */ function burn(uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts/utils/StorageSlot.sol"; import "../../../acl/access-controlled/AccessControlledUpgradeable.sol"; import "../configuration/ConfigurationControlled.sol"; import "../whitelist/IWhitelistManager.sol"; import "../tiers/ITierPricingManager.sol"; import "../../../common/BlockAware.sol"; import "../configuration/Features.sol"; import "./ISaleManager.sol"; import "../../IZeeNFT.sol"; contract SaleManager is ISaleManager, UUPSUpgradeable, ConfigurationControlled, AccessControlledUpgradeable, BlockAware { // TODO move state variables to a storage contract address internal _vault; IZeeNFT internal _zeeNFT; IWhitelistManager internal _whitelistManager; ITierPricingManager internal _tierManager; uint64 internal _tokensBoughtViaPublicMint; mapping(address => uint256) internal _tokensBoughtViaPublicMintPerUser; modifier saleIsActive() { ITierPricingManager.Tier memory tier = _tierManager.getLastTier(); if (_tokensBoughtViaPublicMint >= tier.threshold) revert MintingLimitReached(); _; } /// @dev Constructor that gets called for the implementation contract. constructor() initializer { // solhint-disable-previous-line no-empty-blocks } // solhint-disable-next-line comprehensive-interface function initialize( address configuration, address acl, address whitelistManager, address tierManager, address zeeNft, address vault ) external initializer { // TODO: check that the whitelist manager is actually a whitelist manager // TODO: check that the tier manager is actually a tier manager // TODO: check that the zeeNft is actually a zeeNft __BlockAware_init(); __ConfigurationControlled_init(configuration); __AccessControlled_init(acl); _vault = vault; _zeeNFT = IZeeNFT(zeeNft); _whitelistManager = IWhitelistManager(whitelistManager); _tierManager = ITierPricingManager(tierManager); } /// @inheritdoc ISaleManager receive() external payable override { // solhint-disable-previous-line ordering bytes32[] memory proof = new bytes32[](0); (ITierPricingManager.Tier memory tier, uint256 tierIndex, uint256 totalTiers) = _tierManager.getCurrentTier(); uint256 price = tier.price; if (msg.value < price || msg.value % price != 0) revert InvalidFundsSent(); uint256 count = msg.value / price; _transferAndMint(proof, uint64(count), tier, tierIndex, totalTiers); } function buy(bytes32[] calldata whitelistProof, uint64 count) external payable override { (ITierPricingManager.Tier memory tier, uint256 tierIndex, uint256 totalTiers) = _tierManager.getCurrentTier(); _transferAndMint(whitelistProof, count, tier, tierIndex, totalTiers); } /// @notice transfer ETH to the vault account, mint a new token /// @dev will revert if current purchase count exceeds the current tier /// @dev will revert if ETH amount is not exactly equal to the token price /// @dev will revert if the user has reached his personal mint limit /// @dev will revert if the public token sale limit has been reached /// @dev manages the public sale token tracker // solhint-disable-next-line code-complexity function _transferAndMint( bytes32[] memory whitelistProof, uint64 count, ITierPricingManager.Tier memory tier, uint256 currentTierIndex, uint256 totalTiers ) internal whenEnabled(Features._MINTING) saleIsActive { if (!_whitelistManager.isUserWhitelisted(msg.sender, whitelistProof)) revert NotWhitelisted(); uint64 newPublicMintCount = _tokensBoughtViaPublicMint + count; if (count == 0) revert CannotPurchaseZeroTokens(); if (newPublicMintCount > tier.threshold) revert PurchaseExceedsCurrentTier(); if (tier.capPerUser <= _tokensBoughtViaPublicMintPerUser[msg.sender]) revert UserPurchasingCapReached(); if (msg.value != (tier.price * count)) revert InsufficientFunds(); // Shift the tier index if ( // Only if the currently minted tokens exceed the current threshold (newPublicMintCount >= tier.threshold) && // Only if it is not the very last threshold (currentTierIndex < totalTiers - 1) ) { _tierManager.bumpTier(); } // Buy tokens _tokensBoughtViaPublicMint = newPublicMintCount; _tokensBoughtViaPublicMintPerUser[msg.sender] += count; // Mint the actual tokens _zeeNFT.mint(msg.sender, count); AddressUpgradeable.sendValue(payable(_vault), msg.value); } /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal override onlyAdmin { // solhint-disable-previous-line no-empty-blocks } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts/utils/StorageSlot.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "./IConfiguration.sol"; abstract contract ConfigurationControlled is Initializable { error FeatureEnabled(uint8 feature); error FeatureDisabled(uint8 feature); bytes32 private constant _CONFIGURATION_SLOT = bytes32(uint256(keccak256("zee-game.configuration.slot")) - 1); modifier whenEnabled(uint8 feature) { if (!_getFeature(feature)) revert FeatureDisabled(feature); _; } modifier whenDisabled(uint8 feature) { if (_getFeature(feature)) revert FeatureEnabled(feature); _; } // solhint-disable-next-line func-name-mixedcase function __ConfigurationControlled_init(address configuration) internal onlyInitializing { // TODO interface check StorageSlot.getAddressSlot(_CONFIGURATION_SLOT).value = configuration; } function _enableFeature(uint8 feature) internal { return _getConfiguration().setFeature(feature, true); } function _disableFeature(uint8 feature) internal { return _getConfiguration().setFeature(feature, false); } function _getConfiguration() internal view returns (IConfiguration) { return IConfiguration(StorageSlot.getAddressSlot(_CONFIGURATION_SLOT).value); } function _getFeature(uint8 feature) internal view returns (bool) { return _getConfiguration().getFeature(feature); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; /// @notice Interface that public whitelist interaction. interface IWhitelistManager { /// @notice Thrown when attempting to enable the the merkle root validation without setting the merkle root prior.. error MerkleRootNotSet(); /// @notice Thrown when attempting to call a whitelist-protected method, whilst a user has not been whitelisted.. error NotWhitelisted(); /// @notice Emitted when the merkle root has been set. event MerkleRootSet(bytes32 merkleRoot); /// @notice Emitted when a user has been added to the whitelist manually. event AddedToWhitelist(address account); /// @notice Emitted when a user has been removed from the whitelist. event RemovedFromWhitelist(address account); struct WhitelistOverride { bool blocked; bool whitelisted; } /// @notice Set the merkle root for Whitelist validation. /// @param merkleRoot The merkle root. function setWhitelistMerkleRoot(bytes32 merkleRoot) external; /// @notice Enable whitelist merkle root validation. /// @dev The whitelist merkle root needs to be set to enable this. function enableWhitelist() external; /// @notice Disables the whitelist merkle root validation. /// @dev The whitelist validation features needs to be enabled to call this. function disableWhitelist() external; /// @notice Check if the user has been whitelisted either through Merkle Root or manually. function isUserWhitelisted(address account, bytes32[] memory proof) external returns (bool); /// @notice Add user to the whitelist manually. function addUserToWhitelist(address account) external; /// @notice Remove user from the whitelist manually. function removeUserFromWhitelist(address account) external; /// @notice Get the Whitelist specific merkle root. /// @return bytes32 merkle root function getWhitelistMerkleRoot() external returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; interface ITierPricingManager { /// @notice Emitted when the current tier index has been shifted. event CurrentTierSet(Tier newCurrentTier); /// @notice Emitted when a new set of tiers has been set. event TiersUpdated(Tier[] tiers); /// @notice Emitted when the public token mint limit has been set. event PublicTokenLimitSet(uint256 publicMintTokenLimit); /// @notice Thrown when the supplied tier size is not. error TierMustContainAtLeastOneEntry(); /// @notice Thrown when the tier threshold is smaller than the previous tier. error InvalidTierThresholdSupplied(uint256 tierIndex); /// @notice Thrown when the user-cap is smaller than the previous tier. error InvalidTierCapPerUser(uint256 tierIndex); /// @notice Thrown when user cap is larger than the tier threshold. error TierCapLargerThanThreshold(uint256 tierIndex, uint256 cap, uint256 threshold); struct Tier { /// @dev The price for a single item uint256 price; /// @dev Total amount of total tokens that can be minted uint64 threshold; /// @dev Total amount of tokens that can be bought by a single user uint64 capPerUser; } /// @notice Set tiers. /// @param tiers An array of token-sale describing tiers. The order of the tiers in the array is important. /// price - The price for a single NFT. /// threshold - Total amount of total tokens that can be minted. Each subsequent threshold needs to be larger then the previous one. /// capPerUser - Total amount of tokens that can be bought by a single user. Each subsequent cap needs to be larger or equal than the previous one. function setTiers(Tier[] calldata tiers) external; /// @notice Bump the tier index. function bumpTier() external; /// @notice Get currently stored tier settings. /// @return tiers An array of token-sale describing tiers. function getTiers() external view returns (Tier[] memory tiers); /// @notice Get information regarding the current tier. /// @return currentTier The current tier structure. /// @return currentTierIndex The index of the current tier withing the `tiers` array. /// @return totalTiers The total number of tiers. function getCurrentTier() external returns ( Tier memory currentTier, uint256 currentTierIndex, uint256 totalTiers ); /// @notice Get information about the very last tier. function getLastTier() external returns (Tier memory lastTier); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; library Features { uint8 internal constant _CONFIGURING = 0; uint8 internal constant _MINTING = 1; uint8 internal constant _REVEALING = 2; uint8 internal constant _WHITELIST = 3; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; interface ISaleManager { /// @notice Thrown when attempting to call a whitelist-protected method, whilst a user has not been whitelisted.. error NotWhitelisted(); /// @notice thrown when minting limit has been reached. error MintingLimitReached(); /// @notice Thrown when a user send invalid amount of funds to perform a token purchase. error InvalidFundsSent(); /// @notice Thrown when a user attempts to purchase 0 tokens. error CannotPurchaseZeroTokens(); /// @notice Thrown when a user is attempting to purchase tokens that overlap with the existing. error PurchaseExceedsCurrentTier(); /// @notice Thrown when a user is attempting to purchase more tokens than the user cap allows on the current tier. error UserPurchasingCapReached(); /// @notice thrown when not enough (or too much) ETH has been sent when performing a purchase. error InsufficientFunds(); /// @notice Mint new token by paying the token price receive() external payable; /// @notice Mint new token by paying the token price. /// @param whitelistProof Optional whitelist proof. Used for validating the merkle root. /// If Whitelist feature has been disabled, then this can be an empty array. /// @param count The amount of tokens to purchase in a single transaction. function buy(bytes32[] calldata whitelistProof, uint64 count) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; interface IConfiguration { /// @notice Emitted when the feature changes it's state. event FeatureChanged(uint8 indexed feature, bool value); function setFeature(uint8 feature, bool value) external; function getFeatures() external view returns (uint256); function getFeature(uint8 feature) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import "@openzeppelin/contracts/utils/StorageSlot.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "../../../acl/access-controlled/AccessControlledUpgradeable.sol"; import "../configuration/ConfigurationControlled.sol"; import "../../../common/BlockAware.sol"; import "../configuration/Features.sol"; import "./IWhitelistManager.sol"; contract WhitelistManager is IWhitelistManager, UUPSUpgradeable, ConfigurationControlled, AccessControlledUpgradeable, BlockAware { bytes32 private constant _WHITELIST_MERKLE_ROOT_SLOT = bytes32(uint256(keccak256("zee-game.whitelist.merkle-root")) - 1); mapping(address => WhitelistOverride) private _whitelistOverrides; /// @dev Constructor that gets called for the implementation contract. constructor() initializer { // solhint-disable-previous-line no-empty-blocks } // solhint-disable-next-line comprehensive-interface function initialize(address configuration, address acl) external initializer { __BlockAware_init(); __UUPSUpgradeable_init(); __ConfigurationControlled_init(configuration); __AccessControlled_init(acl); } /// @inheritdoc IWhitelistManager function addUserToWhitelist(address account) external override whenEnabled(Features._WHITELIST) onlyMaintainer { _whitelistOverrides[account] = WhitelistOverride({blocked: false, whitelisted: true}); emit AddedToWhitelist(account); } /// @inheritdoc IWhitelistManager function removeUserFromWhitelist(address account) external override onlyMaintainer { _whitelistOverrides[account] = WhitelistOverride({blocked: true, whitelisted: false}); emit RemovedFromWhitelist(account); } /// @inheritdoc IWhitelistManager function setWhitelistMerkleRoot(bytes32 merkleRoot) external override onlyMaintainer whenEnabled(Features._CONFIGURING) { StorageSlot.getBytes32Slot(_WHITELIST_MERKLE_ROOT_SLOT).value = merkleRoot; emit MerkleRootSet(merkleRoot); } /// @inheritdoc IWhitelistManager function enableWhitelist() external override onlyMaintainer whenDisabled(Features._WHITELIST) { if (_getWhitelistMerkleRoot() == bytes32(0)) revert MerkleRootNotSet(); _enableFeature(Features._WHITELIST); } /// @inheritdoc IWhitelistManager function disableWhitelist() external override onlyMaintainer whenEnabled(Features._WHITELIST) { _disableFeature(Features._WHITELIST); } /// @inheritdoc IWhitelistManager function isUserWhitelisted(address account, bytes32[] memory whitelistProof) external view override returns (bool) { return _isUserWhitelisted(account, whitelistProof); } /// @inheritdoc IWhitelistManager function getWhitelistMerkleRoot() external view override returns (bytes32) { return _getWhitelistMerkleRoot(); } /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal override onlyAdmin { // solhint-disable-previous-line no-empty-blocks } /// @dev Verify if the merkle proof is valid. function _isValidMerkleProof(address account, bytes32[] memory proof) internal view returns (bool) { return MerkleProof.verify(proof, _getWhitelistMerkleRoot(), _constructHash(account)); } /// @dev Construct the hash used for merkle root validation. function _constructHash(address account) internal view returns (bytes32) { return keccak256(abi.encodePacked(address(this), account, block.chainid)); } /// @dev Return the merkle root. function _getWhitelistMerkleRoot() internal view virtual returns (bytes32) { return StorageSlot.getBytes32Slot(_WHITELIST_MERKLE_ROOT_SLOT).value; } /// @dev Make sure that the user has been whitelisted. /// @dev if the user has been manually whitelisted, the `whitelistProof` can be an empty array. function _isUserWhitelisted(address account, bytes32[] memory whitelistProof) internal view returns (bool) { // Everyone is whitelisted while the whitelist is disabled. if (_getFeature(Features._WHITELIST)) { return !_whitelistOverrides[account].blocked && (_whitelistOverrides[account].whitelisted || _isValidMerkleProof(account, whitelistProof)); } return true; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Trees proofs. * * The proofs can be generated using the JavaScript library * https://github.com/miguelmota/merkletreejs[merkletreejs]. * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. * * See `test/utils/cryptography/MerkleProof.test.js` for some examples. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i]; if (computedHash <= proofElement) { // Hash(current computed hash + current element of the proof) computedHash = _efficientHash(computedHash, proofElement); } else { // Hash(current element of the proof + current computed hash) computedHash = _efficientHash(proofElement, computedHash); } } return computedHash; } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "./ITierPricingManager.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts/utils/StorageSlot.sol"; import "../../../acl/access-controlled/AccessControlledUpgradeable.sol"; import "../configuration/ConfigurationControlled.sol"; import "../../../common/BlockAware.sol"; import "../configuration/Features.sol"; contract TierPricingManager is ITierPricingManager, UUPSUpgradeable, ConfigurationControlled, AccessControlledUpgradeable, BlockAware { // TODO move storage variables to a storage contract uint256 internal _currentTierIndex; Tier[] internal _tiers; /// @dev Constructor that gets called for the implementation contract. constructor() initializer { // solhint-disable-previous-line no-empty-blocks } // solhint-disable-next-line comprehensive-interface function initialize(address configuration, address acl) external initializer { __BlockAware_init(); __UUPSUpgradeable_init(); __ConfigurationControlled_init(configuration); __AccessControlled_init(acl); } /// @inheritdoc ITierPricingManager function setTiers(Tier[] calldata tiers) external override onlyMaintainer whenEnabled(Features._CONFIGURING) { delete _tiers; if (tiers.length == 0) revert TierMustContainAtLeastOneEntry(); // TODO can we use a do-while loop here? _checkValidCap(0, tiers[0]); _tiers.push(tiers[0]); for (uint256 i = 1; i < tiers.length; i++) { // Validate that each threshold is strictly larger to the previous if (tiers[i - 1].threshold >= tiers[i].threshold) revert InvalidTierThresholdSupplied(i); // Validate that each user-specific token cap is larger or equal to the previous if (tiers[i - 1].capPerUser > tiers[i].capPerUser) revert InvalidTierCapPerUser(i); _checkValidCap(i, tiers[i]); _tiers.push(tiers[i]); } uint64 publicMintTokenLimit = tiers[tiers.length - 1].threshold; emit TiersUpdated(tiers); emit CurrentTierSet(tiers[0]); emit PublicTokenLimitSet(publicMintTokenLimit); } /// @inheritdoc ITierPricingManager function bumpTier() external override { _currentTierIndex += 1; emit CurrentTierSet(_tiers[_currentTierIndex]); } /// @inheritdoc ITierPricingManager function getTiers() external view override returns (Tier[] memory tiers) { tiers = _tiers; } /// @inheritdoc ITierPricingManager function getCurrentTier() external view override returns ( Tier memory currentTier, uint256 currentTierIndex, uint256 totalTiers ) { currentTier = _tiers[_currentTierIndex]; currentTierIndex = _currentTierIndex; totalTiers = _tiers.length; } /// @inheritdoc ITierPricingManager function getLastTier() external view override returns (Tier memory lastTier) { lastTier = _tiers[_tiers.length - 1]; } /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal override onlyAdmin { // solhint-disable-previous-line no-empty-blocks } function _checkValidCap(uint256 index, Tier memory tier) internal pure { if (tier.capPerUser > tier.threshold) revert TierCapLargerThanThreshold(index, tier.capPerUser, tier.threshold); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @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, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @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. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory _data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @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 (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits a {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits a {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * 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, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.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 be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * 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.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../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: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 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); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.0; import "../ERC721.sol"; import "./IERC721Enumerable.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * 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, ``from``'s `tokenId` will be burned. * - `from` cannot be the zero address. * - `to` cannot be the zero address. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override { super._beforeTokenTransfer(from, to, tokenId); if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import "./IWhitelist.sol"; /// @notice Abstract Whitelist provider contract. /// Encapuslates merkle root validation with proofs + hash construction. abstract contract Whitelist is IWhitelist { /// @dev Verify if the merkle proof is valid. function _isValidMerkleProof(address account, bytes32[] memory proof) internal view returns (bool) { return MerkleProof.verify(proof, _getWhitelistMerkleRoot(), _constructHash(account)); } /// @dev Construct the hash used for merkle root validation. function _constructHash(address account) internal view returns (bytes32) { return keccak256(abi.encodePacked(address(this), account, block.chainid)); } /// @dev Return the merkle root. function _getWhitelistMerkleRoot() internal view virtual returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; /// @notice Interface that public whitelist interaction. interface IWhitelist { /// @notice Set the merkle root for Whitelist validation. /// @param merkleRoot The merkle root. function setWhitelistMerkleRoot(bytes32 merkleRoot) external; /// @notice Check if the user has been whitelisted either through Merkle Root or manually. function isUserWhitelisted(address account, bytes32[] memory proof) external returns (bool); /// @notice Get the Whitelist specific merkle root. /// @return bytes32 merkle root function getWhitelistMerkleRoot() external returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.0; import "../Proxy.sol"; import "./ERC1967Upgrade.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializating the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) payable { assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); _upgradeToAndCall(_logic, _data, false); } /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive() external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overridden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; // Importing `ERC1967Proxy` so we can access it from our deploy scripts import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import "@openzeppelin/contracts-upgradeable/utils/structs/BitMapsUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "../../../acl/access-controlled/AccessControlledUpgradeable.sol"; import "../../../common/BlockAware.sol"; import "./IConfiguration.sol"; contract Configuration is IConfiguration, UUPSUpgradeable, AccessControlledUpgradeable, BlockAware { using BitMapsUpgradeable for BitMapsUpgradeable.BitMap; BitMapsUpgradeable.BitMap internal _features; /// @dev Constructor that gets called for the implementation contract. constructor() initializer { // solhint-disable-previous-line no-empty-blocks } function initialize(address acl) external initializer { // solhint-disable-previous-line comprehensive-interface __BlockAware_init(); __UUPSUpgradeable_init(); __AccessControlled_init(acl); } /// @inheritdoc IConfiguration function setFeature(uint8 feature, bool value) external override onlyRole(Roles.AUXILIARY_CONTRACTS) { _features.setTo(feature, value); emit FeatureChanged(feature, value); } /// @inheritdoc IConfiguration function getFeature(uint8 feature) external view override returns (bool) { return _featureIsEnabled(feature); } /// @inheritdoc IConfiguration function getFeatures() external view override returns (uint256) { return _features._data[0]; } /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal override onlyAdmin { // solhint-disable-previous-line no-empty-blocks } function _featureIsEnabled(uint8 feature) internal view returns (bool) { return _features.get(feature); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/structs/BitMaps.sol) pragma solidity ^0.8.0; /** * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. */ library BitMapsUpgradeable { struct BitMap { mapping(uint256 => uint256) _data; } /** * @dev Returns whether the bit at `index` is set. */ function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); return bitmap._data[bucket] & mask != 0; } /** * @dev Sets the bit at `index` to the boolean `value`. */ function setTo( BitMap storage bitmap, uint256 index, bool value ) internal { if (value) { set(bitmap, index); } else { unset(bitmap, index); } } /** * @dev Sets the bit at `index`. */ function set(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] |= mask; } /** * @dev Unsets the bit at `index`. */ function unset(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] &= ~mask; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"MerkleRootSet","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MAX_PUBLIC_MINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"canMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWhitelistMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"whitelistProof","type":"bytes32[]"}],"name":"isUserWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"whitelistProof","type":"bytes32[]"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publiclyMintedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"n","type":"uint256"}],"name":"reserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"newState","type":"bool"}],"name":"setMintState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"setWhitelistMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080604052600a805460ff60a01b191690556000600d819055600e819055600f8190556010553480156200003257600080fd5b50604080518082018252600b81526a4d61736b206f66205a454560a81b60208083019182528351808501909452600384526226b7ad60e91b908401528151919291620000819160009162000110565b5080516200009790600190602084019062000110565b505050620000b4620000ae620000ba60201b60201c565b620000be565b620001f2565b3390565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8280546200011e90620001b6565b90600052602060002090601f0160209004810192826200014257600085556200018d565b82601f106200015d57805160ff19168380011785556200018d565b828001600101855582156200018d579182015b828111156200018d57825182559160200191906001019062000170565b506200019b9291506200019f565b5090565b5b808211156200019b5760008155600101620001a0565b600181811c90821680620001cb57607f821691505b602082108103620001ec57634e487b7160e01b600052602260045260246000fd5b50919050565b61224680620002026000396000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806365f130971161010f578063b88d4fde116100a2578063e985e9c511610071578063e985e9c51461041d578063ebae70b314610459578063ef7922e314610461578063f2fde38b1461046957600080fd5b8063b88d4fde146103b7578063bd32fb66146103ca578063c2ba4744146103dd578063c87b56dd1461040a57600080fd5b80638da5cb5b116100de5780638da5cb5b1461037857806395d89b4114610389578063a22cb46514610391578063b77a147b146103a457600080fd5b806365f130971461034157806370a082311461034a578063715018a61461035d578063819b25ba1461036557600080fd5b806332cb6b0c116101875780634f6ccce7116101565780634f6ccce7146102f557806353483c9d1461030857806355f804b31461031b5780636352211e1461032e57600080fd5b806332cb6b0c146102bd5780633ccfd60b146102c657806342842e0e146102ce578063471a4294146102e157600080fd5b806318160ddd116101c357806318160ddd1461027257806323b872dd1461028457806326412aca146102975780632f745c59146102aa57600080fd5b806301ffc9a7146101f557806306fdde031461021d578063081812fc14610232578063095ea7b31461025d575b600080fd5b610208610203366004611b80565b61047c565b60405190151581526020015b60405180910390f35b61022561048d565b6040516102149190611bf5565b610245610240366004611c08565b61051f565b6040516001600160a01b039091168152602001610214565b61027061026b366004611c3d565b6105b9565b005b6008545b604051908152602001610214565b610270610292366004611c67565b6106ce565b6102706102a5366004611cb3565b6106ff565b6102766102b8366004611c3d565b610747565b610276610d0581565b6102706107dd565b6102706102dc366004611c67565b61083a565b600a5461020890600160a01b900460ff1681565b610276610303366004611c08565b610855565b610208610316366004611d95565b6108e8565b610270610329366004611e3b565b6108fb565b61024561033c366004611c08565b610938565b610276610bb881565b610276610358366004611e84565b6109af565b610270610a36565b610270610373366004611c08565b610a6c565b600a546001600160a01b0316610245565b610225610ad3565b61027061039f366004611e9f565b610ae2565b6102706103b2366004611ed2565b610aed565b6102706103c5366004611f07565b610cea565b6102706103d8366004611c08565b610d22565b6102086103eb366004611e84565b6001600160a01b031660009081526011602052604090205460ff161590565b610225610418366004611c08565b610d87565b61020861042b366004611f83565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600d54610276565b610276610e61565b610270610477366004611e84565b610e71565b600061048782610f0c565b92915050565b60606000805461049c90611fad565b80601f01602080910402602001604051908101604052809291908181526020018280546104c890611fad565b80156105155780601f106104ea57610100808354040283529160200191610515565b820191906000526020600020905b8154815290600101906020018083116104f857829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b031661059d5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b60006105c482610938565b9050806001600160a01b0316836001600160a01b0316036106315760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610594565b336001600160a01b038216148061064d575061064d813361042b565b6106bf5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610594565b6106c98383610f31565b505050565b6106d83382610f9f565b6106f45760405162461bcd60e51b815260040161059490611fe7565b6106c9838383611096565b600a546001600160a01b031633146107295760405162461bcd60e51b815260040161059490612038565b600a8054911515600160a01b0260ff60a01b19909216919091179055565b6000610752836109af565b82106107b45760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610594565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b600a546001600160a01b031633146108075760405162461bcd60e51b815260040161059490612038565b6040514790339082156108fc029083906000818181858888f19350505050158015610836573d6000803e3d6000fd5b5050565b6106c983838360405180602001604052806000815250610cea565b600061086060085490565b82106108c35760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610594565b600882815481106108d6576108d661206d565b90600052602060002001549050919050565b60006108f4838361123d565b9392505050565b600a546001600160a01b031633146109255760405162461bcd60e51b815260040161059490612038565b805161083690600b906020840190611ad1565b6000818152600260205260408120546001600160a01b0316806104875760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610594565b60006001600160a01b038216610a1a5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610594565b506001600160a01b031660009081526003602052604090205490565b600a546001600160a01b03163314610a605760405162461bcd60e51b815260040161059490612038565b610a6a60006112a5565b565b600a546001600160a01b03163314610a965760405162461bcd60e51b815260040161059490612038565b6000610aa160085490565b905060005b828110156106c957610ac133610abc8385612099565b6112f7565b80610acb816120b1565b915050610aa6565b60606001805461049c90611fad565b610836338383611311565b6000610af860085490565b3360009081526011602052604090205490915060ff1615610b6d5760405162461bcd60e51b815260206004820152602960248201527f4f6e6c792073696e676c65206974656d2063616e206265206d696e7465642070604482015268195c881dd85b1b195d60ba1b6064820152608401610594565b600a54600160a01b900460ff16610bc65760405162461bcd60e51b815260206004820152601960248201527f4d696e74696e67206e6f742079657420616374697661746564000000000000006044820152606401610594565b610d058110610c175760405162461bcd60e51b815260206004820152601c60248201527f4d696e7420776f756c6420657863656564206d617820746f6b656e73000000006044820152606401610594565b610bb8600d5410610c5e5760405162461bcd60e51b8152602060048201526011602482015270105b1b081d1bdad95b9cc81b5a5b9d1959607a1b6044820152606401610594565b610c68338361123d565b610cad5760405162461bcd60e51b815260206004820152601660248201527515d85b1b195d081b9bdd081dda1a5d195b1a5cdd195960521b6044820152606401610594565b336000818152601160205260409020805460ff19166001179055610cd190826112f7565b600d8054906000610ce1836120b1565b91905055505050565b610cf43383610f9f565b610d105760405162461bcd60e51b815260040161059490611fe7565b610d1c848484846113df565b50505050565b600a546001600160a01b03163314610d4c5760405162461bcd60e51b815260040161059490612038565b600c8190556040518181527f42cbc405e4dbf1b691e85b9a34b08ecfcf7a9ad9078bf4d645ccfa1fac11c10b9060200160405180910390a150565b6000818152600260205260409020546060906001600160a01b0316610e065760405162461bcd60e51b815260206004820152602f60248201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b6064820152608401610594565b6000610e10611412565b90506000815111610e3057604051806020016040528060008152506108f4565b80610e3a84611421565b604051602001610e4b9291906120ca565b6040516020818303038152906040529392505050565b6000610e6c600c5490565b905090565b600a546001600160a01b03163314610e9b5760405162461bcd60e51b815260040161059490612038565b6001600160a01b038116610f005760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610594565b610f09816112a5565b50565b60006001600160e01b0319821663780e9d6360e01b1480610487575061048782611522565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610f6682610938565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b03166110185760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610594565b600061102383610938565b9050806001600160a01b0316846001600160a01b0316148061106a57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b8061108e5750836001600160a01b03166110838461051f565b6001600160a01b0316145b949350505050565b826001600160a01b03166110a982610938565b6001600160a01b03161461110d5760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610594565b6001600160a01b03821661116f5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610594565b61117a838383611572565b611185600082610f31565b6001600160a01b03831660009081526003602052604081208054600192906111ae9084906120f9565b90915550506001600160a01b03821660009081526003602052604081208054600192906111dc908490612099565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60006108f48261124c600c5490565b6112a0866040516bffffffffffffffffffffffff1930606090811b8216602084015283901b166034820152466048820152600090606801604051602081830303815290604052805190602001209050919050565b61157d565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b610836828260405180602001604052806000815250611593565b816001600160a01b0316836001600160a01b0316036113725760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610594565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6113ea848484611096565b6113f6848484846115c6565b610d1c5760405162461bcd60e51b815260040161059490612110565b6060600b805461049c90611fad565b6060816000036114485750506040805180820190915260018152600360fc1b602082015290565b8160005b8115611472578061145c816120b1565b915061146b9050600a83612178565b915061144c565b60008167ffffffffffffffff81111561148d5761148d611cce565b6040519080825280601f01601f1916602001820160405280156114b7576020820181803683370190505b5090505b841561108e576114cc6001836120f9565b91506114d9600a8661218c565b6114e4906030612099565b60f81b8183815181106114f9576114f961206d565b60200101906001600160f81b031916908160001a90535061151b600a86612178565b94506114bb565b60006001600160e01b031982166380ac58cd60e01b148061155357506001600160e01b03198216635b5e139f60e01b145b8061048757506301ffc9a760e01b6001600160e01b0319831614610487565b6106c98383836116c7565b60008261158a858461177f565b14949350505050565b61159d83836117f3565b6115aa60008484846115c6565b6106c95760405162461bcd60e51b815260040161059490612110565b60006001600160a01b0384163b156116bc57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061160a9033908990889088906004016121a0565b6020604051808303816000875af1925050508015611645575060408051601f3d908101601f19168201909252611642918101906121dd565b60015b6116a2573d808015611673576040519150601f19603f3d011682016040523d82523d6000602084013e611678565b606091505b50805160000361169a5760405162461bcd60e51b815260040161059490612110565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061108e565b506001949350505050565b6001600160a01b0383166117225761171d81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611745565b816001600160a01b0316836001600160a01b031614611745576117458382611941565b6001600160a01b03821661175c576106c9816119de565b826001600160a01b0316826001600160a01b0316146106c9576106c98282611a8d565b600081815b84518110156117eb5760008582815181106117a1576117a161206d565b602002602001015190508083116117c757600083815260208290526040902092506117d8565b600081815260208490526040902092505b50806117e3816120b1565b915050611784565b509392505050565b6001600160a01b0382166118495760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610594565b6000818152600260205260409020546001600160a01b0316156118ae5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610594565b6118ba60008383611572565b6001600160a01b03821660009081526003602052604081208054600192906118e3908490612099565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000600161194e846109af565b61195891906120f9565b6000838152600760205260409020549091508082146119ab576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b6008546000906119f0906001906120f9565b60008381526009602052604081205460088054939450909284908110611a1857611a1861206d565b906000526020600020015490508060088381548110611a3957611a3961206d565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480611a7157611a716121fa565b6001900381819060005260206000200160009055905550505050565b6000611a98836109af565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b828054611add90611fad565b90600052602060002090601f016020900481019282611aff5760008555611b45565b82601f10611b1857805160ff1916838001178555611b45565b82800160010185558215611b45579182015b82811115611b45578251825591602001919060010190611b2a565b50611b51929150611b55565b5090565b5b80821115611b515760008155600101611b56565b6001600160e01b031981168114610f0957600080fd5b600060208284031215611b9257600080fd5b81356108f481611b6a565b60005b83811015611bb8578181015183820152602001611ba0565b83811115610d1c5750506000910152565b60008151808452611be1816020860160208601611b9d565b601f01601f19169290920160200192915050565b6020815260006108f46020830184611bc9565b600060208284031215611c1a57600080fd5b5035919050565b80356001600160a01b0381168114611c3857600080fd5b919050565b60008060408385031215611c5057600080fd5b611c5983611c21565b946020939093013593505050565b600080600060608486031215611c7c57600080fd5b611c8584611c21565b9250611c9360208501611c21565b9150604084013590509250925092565b80358015158114611c3857600080fd5b600060208284031215611cc557600080fd5b6108f482611ca3565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611d0d57611d0d611cce565b604052919050565b600082601f830112611d2657600080fd5b8135602067ffffffffffffffff821115611d4257611d42611cce565b8160051b611d51828201611ce4565b9283528481018201928281019087851115611d6b57600080fd5b83870192505b84831015611d8a57823582529183019190830190611d71565b979650505050505050565b60008060408385031215611da857600080fd5b611db183611c21565b9150602083013567ffffffffffffffff811115611dcd57600080fd5b611dd985828601611d15565b9150509250929050565b600067ffffffffffffffff831115611dfd57611dfd611cce565b611e10601f8401601f1916602001611ce4565b9050828152838383011115611e2457600080fd5b828260208301376000602084830101529392505050565b600060208284031215611e4d57600080fd5b813567ffffffffffffffff811115611e6457600080fd5b8201601f81018413611e7557600080fd5b61108e84823560208401611de3565b600060208284031215611e9657600080fd5b6108f482611c21565b60008060408385031215611eb257600080fd5b611ebb83611c21565b9150611ec960208401611ca3565b90509250929050565b600060208284031215611ee457600080fd5b813567ffffffffffffffff811115611efb57600080fd5b61108e84828501611d15565b60008060008060808587031215611f1d57600080fd5b611f2685611c21565b9350611f3460208601611c21565b925060408501359150606085013567ffffffffffffffff811115611f5757600080fd5b8501601f81018713611f6857600080fd5b611f7787823560208401611de3565b91505092959194509250565b60008060408385031215611f9657600080fd5b611f9f83611c21565b9150611ec960208401611c21565b600181811c90821680611fc157607f821691505b602082108103611fe157634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082198211156120ac576120ac612083565b500190565b6000600182016120c3576120c3612083565b5060010190565b600083516120dc818460208801611b9d565b8351908301906120f0818360208801611b9d565b01949350505050565b60008282101561210b5761210b612083565b500390565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b60008261218757612187612162565b500490565b60008261219b5761219b612162565b500690565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906121d390830184611bc9565b9695505050505050565b6000602082840312156121ef57600080fd5b81516108f481611b6a565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220f996246cdd1aec30230a5aadf424675feeb82c40e5230faba3446518bfa106ad64736f6c634300080e0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806365f130971161010f578063b88d4fde116100a2578063e985e9c511610071578063e985e9c51461041d578063ebae70b314610459578063ef7922e314610461578063f2fde38b1461046957600080fd5b8063b88d4fde146103b7578063bd32fb66146103ca578063c2ba4744146103dd578063c87b56dd1461040a57600080fd5b80638da5cb5b116100de5780638da5cb5b1461037857806395d89b4114610389578063a22cb46514610391578063b77a147b146103a457600080fd5b806365f130971461034157806370a082311461034a578063715018a61461035d578063819b25ba1461036557600080fd5b806332cb6b0c116101875780634f6ccce7116101565780634f6ccce7146102f557806353483c9d1461030857806355f804b31461031b5780636352211e1461032e57600080fd5b806332cb6b0c146102bd5780633ccfd60b146102c657806342842e0e146102ce578063471a4294146102e157600080fd5b806318160ddd116101c357806318160ddd1461027257806323b872dd1461028457806326412aca146102975780632f745c59146102aa57600080fd5b806301ffc9a7146101f557806306fdde031461021d578063081812fc14610232578063095ea7b31461025d575b600080fd5b610208610203366004611b80565b61047c565b60405190151581526020015b60405180910390f35b61022561048d565b6040516102149190611bf5565b610245610240366004611c08565b61051f565b6040516001600160a01b039091168152602001610214565b61027061026b366004611c3d565b6105b9565b005b6008545b604051908152602001610214565b610270610292366004611c67565b6106ce565b6102706102a5366004611cb3565b6106ff565b6102766102b8366004611c3d565b610747565b610276610d0581565b6102706107dd565b6102706102dc366004611c67565b61083a565b600a5461020890600160a01b900460ff1681565b610276610303366004611c08565b610855565b610208610316366004611d95565b6108e8565b610270610329366004611e3b565b6108fb565b61024561033c366004611c08565b610938565b610276610bb881565b610276610358366004611e84565b6109af565b610270610a36565b610270610373366004611c08565b610a6c565b600a546001600160a01b0316610245565b610225610ad3565b61027061039f366004611e9f565b610ae2565b6102706103b2366004611ed2565b610aed565b6102706103c5366004611f07565b610cea565b6102706103d8366004611c08565b610d22565b6102086103eb366004611e84565b6001600160a01b031660009081526011602052604090205460ff161590565b610225610418366004611c08565b610d87565b61020861042b366004611f83565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600d54610276565b610276610e61565b610270610477366004611e84565b610e71565b600061048782610f0c565b92915050565b60606000805461049c90611fad565b80601f01602080910402602001604051908101604052809291908181526020018280546104c890611fad565b80156105155780601f106104ea57610100808354040283529160200191610515565b820191906000526020600020905b8154815290600101906020018083116104f857829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b031661059d5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b60006105c482610938565b9050806001600160a01b0316836001600160a01b0316036106315760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610594565b336001600160a01b038216148061064d575061064d813361042b565b6106bf5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610594565b6106c98383610f31565b505050565b6106d83382610f9f565b6106f45760405162461bcd60e51b815260040161059490611fe7565b6106c9838383611096565b600a546001600160a01b031633146107295760405162461bcd60e51b815260040161059490612038565b600a8054911515600160a01b0260ff60a01b19909216919091179055565b6000610752836109af565b82106107b45760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610594565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b600a546001600160a01b031633146108075760405162461bcd60e51b815260040161059490612038565b6040514790339082156108fc029083906000818181858888f19350505050158015610836573d6000803e3d6000fd5b5050565b6106c983838360405180602001604052806000815250610cea565b600061086060085490565b82106108c35760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610594565b600882815481106108d6576108d661206d565b90600052602060002001549050919050565b60006108f4838361123d565b9392505050565b600a546001600160a01b031633146109255760405162461bcd60e51b815260040161059490612038565b805161083690600b906020840190611ad1565b6000818152600260205260408120546001600160a01b0316806104875760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610594565b60006001600160a01b038216610a1a5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610594565b506001600160a01b031660009081526003602052604090205490565b600a546001600160a01b03163314610a605760405162461bcd60e51b815260040161059490612038565b610a6a60006112a5565b565b600a546001600160a01b03163314610a965760405162461bcd60e51b815260040161059490612038565b6000610aa160085490565b905060005b828110156106c957610ac133610abc8385612099565b6112f7565b80610acb816120b1565b915050610aa6565b60606001805461049c90611fad565b610836338383611311565b6000610af860085490565b3360009081526011602052604090205490915060ff1615610b6d5760405162461bcd60e51b815260206004820152602960248201527f4f6e6c792073696e676c65206974656d2063616e206265206d696e7465642070604482015268195c881dd85b1b195d60ba1b6064820152608401610594565b600a54600160a01b900460ff16610bc65760405162461bcd60e51b815260206004820152601960248201527f4d696e74696e67206e6f742079657420616374697661746564000000000000006044820152606401610594565b610d058110610c175760405162461bcd60e51b815260206004820152601c60248201527f4d696e7420776f756c6420657863656564206d617820746f6b656e73000000006044820152606401610594565b610bb8600d5410610c5e5760405162461bcd60e51b8152602060048201526011602482015270105b1b081d1bdad95b9cc81b5a5b9d1959607a1b6044820152606401610594565b610c68338361123d565b610cad5760405162461bcd60e51b815260206004820152601660248201527515d85b1b195d081b9bdd081dda1a5d195b1a5cdd195960521b6044820152606401610594565b336000818152601160205260409020805460ff19166001179055610cd190826112f7565b600d8054906000610ce1836120b1565b91905055505050565b610cf43383610f9f565b610d105760405162461bcd60e51b815260040161059490611fe7565b610d1c848484846113df565b50505050565b600a546001600160a01b03163314610d4c5760405162461bcd60e51b815260040161059490612038565b600c8190556040518181527f42cbc405e4dbf1b691e85b9a34b08ecfcf7a9ad9078bf4d645ccfa1fac11c10b9060200160405180910390a150565b6000818152600260205260409020546060906001600160a01b0316610e065760405162461bcd60e51b815260206004820152602f60248201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60448201526e3732bc34b9ba32b73a103a37b5b2b760891b6064820152608401610594565b6000610e10611412565b90506000815111610e3057604051806020016040528060008152506108f4565b80610e3a84611421565b604051602001610e4b9291906120ca565b6040516020818303038152906040529392505050565b6000610e6c600c5490565b905090565b600a546001600160a01b03163314610e9b5760405162461bcd60e51b815260040161059490612038565b6001600160a01b038116610f005760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610594565b610f09816112a5565b50565b60006001600160e01b0319821663780e9d6360e01b1480610487575061048782611522565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610f6682610938565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b03166110185760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610594565b600061102383610938565b9050806001600160a01b0316846001600160a01b0316148061106a57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b8061108e5750836001600160a01b03166110838461051f565b6001600160a01b0316145b949350505050565b826001600160a01b03166110a982610938565b6001600160a01b03161461110d5760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610594565b6001600160a01b03821661116f5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610594565b61117a838383611572565b611185600082610f31565b6001600160a01b03831660009081526003602052604081208054600192906111ae9084906120f9565b90915550506001600160a01b03821660009081526003602052604081208054600192906111dc908490612099565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60006108f48261124c600c5490565b6112a0866040516bffffffffffffffffffffffff1930606090811b8216602084015283901b166034820152466048820152600090606801604051602081830303815290604052805190602001209050919050565b61157d565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b610836828260405180602001604052806000815250611593565b816001600160a01b0316836001600160a01b0316036113725760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610594565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6113ea848484611096565b6113f6848484846115c6565b610d1c5760405162461bcd60e51b815260040161059490612110565b6060600b805461049c90611fad565b6060816000036114485750506040805180820190915260018152600360fc1b602082015290565b8160005b8115611472578061145c816120b1565b915061146b9050600a83612178565b915061144c565b60008167ffffffffffffffff81111561148d5761148d611cce565b6040519080825280601f01601f1916602001820160405280156114b7576020820181803683370190505b5090505b841561108e576114cc6001836120f9565b91506114d9600a8661218c565b6114e4906030612099565b60f81b8183815181106114f9576114f961206d565b60200101906001600160f81b031916908160001a90535061151b600a86612178565b94506114bb565b60006001600160e01b031982166380ac58cd60e01b148061155357506001600160e01b03198216635b5e139f60e01b145b8061048757506301ffc9a760e01b6001600160e01b0319831614610487565b6106c98383836116c7565b60008261158a858461177f565b14949350505050565b61159d83836117f3565b6115aa60008484846115c6565b6106c95760405162461bcd60e51b815260040161059490612110565b60006001600160a01b0384163b156116bc57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061160a9033908990889088906004016121a0565b6020604051808303816000875af1925050508015611645575060408051601f3d908101601f19168201909252611642918101906121dd565b60015b6116a2573d808015611673576040519150601f19603f3d011682016040523d82523d6000602084013e611678565b606091505b50805160000361169a5760405162461bcd60e51b815260040161059490612110565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061108e565b506001949350505050565b6001600160a01b0383166117225761171d81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611745565b816001600160a01b0316836001600160a01b031614611745576117458382611941565b6001600160a01b03821661175c576106c9816119de565b826001600160a01b0316826001600160a01b0316146106c9576106c98282611a8d565b600081815b84518110156117eb5760008582815181106117a1576117a161206d565b602002602001015190508083116117c757600083815260208290526040902092506117d8565b600081815260208490526040902092505b50806117e3816120b1565b915050611784565b509392505050565b6001600160a01b0382166118495760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610594565b6000818152600260205260409020546001600160a01b0316156118ae5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610594565b6118ba60008383611572565b6001600160a01b03821660009081526003602052604081208054600192906118e3908490612099565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000600161194e846109af565b61195891906120f9565b6000838152600760205260409020549091508082146119ab576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b6008546000906119f0906001906120f9565b60008381526009602052604081205460088054939450909284908110611a1857611a1861206d565b906000526020600020015490508060088381548110611a3957611a3961206d565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480611a7157611a716121fa565b6001900381819060005260206000200160009055905550505050565b6000611a98836109af565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b828054611add90611fad565b90600052602060002090601f016020900481019282611aff5760008555611b45565b82601f10611b1857805160ff1916838001178555611b45565b82800160010185558215611b45579182015b82811115611b45578251825591602001919060010190611b2a565b50611b51929150611b55565b5090565b5b80821115611b515760008155600101611b56565b6001600160e01b031981168114610f0957600080fd5b600060208284031215611b9257600080fd5b81356108f481611b6a565b60005b83811015611bb8578181015183820152602001611ba0565b83811115610d1c5750506000910152565b60008151808452611be1816020860160208601611b9d565b601f01601f19169290920160200192915050565b6020815260006108f46020830184611bc9565b600060208284031215611c1a57600080fd5b5035919050565b80356001600160a01b0381168114611c3857600080fd5b919050565b60008060408385031215611c5057600080fd5b611c5983611c21565b946020939093013593505050565b600080600060608486031215611c7c57600080fd5b611c8584611c21565b9250611c9360208501611c21565b9150604084013590509250925092565b80358015158114611c3857600080fd5b600060208284031215611cc557600080fd5b6108f482611ca3565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611d0d57611d0d611cce565b604052919050565b600082601f830112611d2657600080fd5b8135602067ffffffffffffffff821115611d4257611d42611cce565b8160051b611d51828201611ce4565b9283528481018201928281019087851115611d6b57600080fd5b83870192505b84831015611d8a57823582529183019190830190611d71565b979650505050505050565b60008060408385031215611da857600080fd5b611db183611c21565b9150602083013567ffffffffffffffff811115611dcd57600080fd5b611dd985828601611d15565b9150509250929050565b600067ffffffffffffffff831115611dfd57611dfd611cce565b611e10601f8401601f1916602001611ce4565b9050828152838383011115611e2457600080fd5b828260208301376000602084830101529392505050565b600060208284031215611e4d57600080fd5b813567ffffffffffffffff811115611e6457600080fd5b8201601f81018413611e7557600080fd5b61108e84823560208401611de3565b600060208284031215611e9657600080fd5b6108f482611c21565b60008060408385031215611eb257600080fd5b611ebb83611c21565b9150611ec960208401611ca3565b90509250929050565b600060208284031215611ee457600080fd5b813567ffffffffffffffff811115611efb57600080fd5b61108e84828501611d15565b60008060008060808587031215611f1d57600080fd5b611f2685611c21565b9350611f3460208601611c21565b925060408501359150606085013567ffffffffffffffff811115611f5757600080fd5b8501601f81018713611f6857600080fd5b611f7787823560208401611de3565b91505092959194509250565b60008060408385031215611f9657600080fd5b611f9f83611c21565b9150611ec960208401611c21565b600181811c90821680611fc157607f821691505b602082108103611fe157634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082198211156120ac576120ac612083565b500190565b6000600182016120c3576120c3612083565b5060010190565b600083516120dc818460208801611b9d565b8351908301906120f0818360208801611b9d565b01949350505050565b60008282101561210b5761210b612083565b500390565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b60008261218757612187612162565b500490565b60008261219b5761219b612162565b500690565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906121d390830184611bc9565b9695505050505050565b6000602082840312156121ef57600080fd5b81516108f481611b6a565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220f996246cdd1aec30230a5aadf424675feeb82c40e5230faba3446518bfa106ad64736f6c634300080e0033
Deployed Bytecode Sourcemap
304:3636:70:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1136:177;;;;;;:::i;:::-;;:::i;:::-;;;565:14:82;;558:22;540:41;;528:2;513:18;1136:177:70;;;;;;;;2488:98:30;;;:::i;:::-;;;;;;;:::i;4000:217::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1692:32:82;;;1674:51;;1662:2;1647:18;4000:217:30;1528:203:82;3538:401:30;;;;;;:::i;:::-;;:::i;:::-;;1615:111:33;1702:10;:17;1615:111;;;2319:25:82;;;2307:2;2292:18;1615:111:33;2173:177:82;4727:330:30;;;;;;:::i;:::-;;:::i;1759:96:70:-;;;;;;:::i;:::-;;:::i;1291:253:33:-;;;;;;:::i;:::-;;:::i;748:41:70:-;;785:4;748:41;;2563:139;;;:::i;5123:179:30:-;;;;;;:::i;:::-;;:::i;481:32:70:-;;;;;-1:-1:-1;;;481:32:70;;;;;;1798:230:33;;;;;;:::i;:::-;;:::i;3280:203:70:-;;;;;;:::i;:::-;;:::i;1319:109::-;;;;;;:::i;:::-;;:::i;2191:235:30:-;;;;;;:::i;:::-;;:::i;795:46:70:-;;837:4;795:46;;1929:205:30;;;;;;:::i;:::-;;:::i;1668:101:24:-;;;:::i;1555:198:70:-;;;;;;:::i;:::-;;:::i;1036:85:24:-;1108:6;;-1:-1:-1;;;;;1108:6:24;1036:85;;2650:102:30;;;:::i;4284:153::-;;;;;;:::i;:::-;;:::i;1978:579:70:-;;;;;;:::i;:::-;;:::i;5368:320:30:-;;;;;;:::i;:::-;;:::i;2739:187:70:-;;;;;;:::i;:::-;;:::i;1861:111::-;;;;;;:::i;:::-;-1:-1:-1;;;;;1940:16:70;1917:4;1940:16;;;:7;:16;;;;;;;;:25;;1861:111;3601:337;;;;;;:::i;:::-;;:::i;4503:162:30:-;;;;;;:::i;:::-;-1:-1:-1;;;;;4623:25:30;;;4600:4;4623:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;4503:162;3489:106:70;3574:14;;3489:106;;2963:124;;;:::i;1918:198:24:-;;;;;;:::i;:::-;;:::i;1136:177:70:-;1247:4;1270:36;1294:11;1270:23;:36::i;:::-;1263:43;1136:177;-1:-1:-1;;1136:177:70:o;2488:98:30:-;2542:13;2574:5;2567:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2488:98;:::o;4000:217::-;4076:7;7248:16;;;:7;:16;;;;;;-1:-1:-1;;;;;7248:16:30;4095:73;;;;-1:-1:-1;;;4095:73:30;;8156:2:82;4095:73:30;;;8138:21:82;8195:2;8175:18;;;8168:30;8234:34;8214:18;;;8207:62;-1:-1:-1;;;8285:18:82;;;8278:42;8337:19;;4095:73:30;;;;;;;;;-1:-1:-1;4186:24:30;;;;:15;:24;;;;;;-1:-1:-1;;;;;4186:24:30;;4000:217::o;3538:401::-;3618:13;3634:23;3649:7;3634:14;:23::i;:::-;3618:39;;3681:5;-1:-1:-1;;;;;3675:11:30;:2;-1:-1:-1;;;;;3675:11:30;;3667:57;;;;-1:-1:-1;;;3667:57:30;;8569:2:82;3667:57:30;;;8551:21:82;8608:2;8588:18;;;8581:30;8647:34;8627:18;;;8620:62;-1:-1:-1;;;8698:18:82;;;8691:31;8739:19;;3667:57:30;8367:397:82;3667:57:30;719:10:37;-1:-1:-1;;;;;3756:21:30;;;;:62;;-1:-1:-1;3781:37:30;3798:5;719:10:37;4503:162:30;:::i;3781:37::-;3735:165;;;;-1:-1:-1;;;3735:165:30;;8971:2:82;3735:165:30;;;8953:21:82;9010:2;8990:18;;;8983:30;9049:34;9029:18;;;9022:62;9120:26;9100:18;;;9093:54;9164:19;;3735:165:30;8769:420:82;3735:165:30;3911:21;3920:2;3924:7;3911:8;:21::i;:::-;3608:331;3538:401;;:::o;4727:330::-;4916:41;719:10:37;4949:7:30;4916:18;:41::i;:::-;4908:103;;;;-1:-1:-1;;;4908:103:30;;;;;;;:::i;:::-;5022:28;5032:4;5038:2;5042:7;5022:9;:28::i;1759:96:70:-;1108:6:24;;-1:-1:-1;;;;;1108:6:24;719:10:37;1248:23:24;1240:68;;;;-1:-1:-1;;;1240:68:24;;;;;;;:::i;:::-;1825:12:70::1;:23:::0;;;::::1;;-1:-1:-1::0;;;1825:23:70::1;-1:-1:-1::0;;;;1825:23:70;;::::1;::::0;;;::::1;::::0;;1759:96::o;1291:253:33:-;1388:7;1423:23;1440:5;1423:16;:23::i;:::-;1415:5;:31;1407:87;;;;-1:-1:-1;;;1407:87:33;;10175:2:82;1407:87:33;;;10157:21:82;10214:2;10194:18;;;10187:30;10253:34;10233:18;;;10226:62;-1:-1:-1;;;10304:18:82;;;10297:41;10355:19;;1407:87:33;9973:407:82;1407:87:33;-1:-1:-1;;;;;;1511:19:33;;;;;;;;:12;:19;;;;;;;;:26;;;;;;;;;1291:253::o;2563:139:70:-;1108:6:24;;-1:-1:-1;;;;;1108:6:24;719:10:37;1248:23:24;1240:68;;;;-1:-1:-1;;;1240:68:24;;;;;;;:::i;:::-;2658:37:70::1;::::0;2627:21:::1;::::0;2666:10:::1;::::0;2658:37;::::1;;;::::0;2627:21;;2612:12:::1;2658:37:::0;2612:12;2658:37;2627:21;2666:10;2658:37;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;2602:100;2563:139::o:0;5123:179:30:-;5256:39;5273:4;5279:2;5283:7;5256:39;;;;;;;;;;;;:16;:39::i;1798:230:33:-;1873:7;1908:30;1702:10;:17;;1615:111;1908:30;1900:5;:38;1892:95;;;;-1:-1:-1;;;1892:95:33;;10587:2:82;1892:95:33;;;10569:21:82;10626:2;10606:18;;;10599:30;10665:34;10645:18;;;10638:62;-1:-1:-1;;;10716:18:82;;;10709:42;10768:19;;1892:95:33;10385:408:82;1892:95:33;2004:10;2015:5;2004:17;;;;;;;;:::i;:::-;;;;;;;;;1997:24;;1798:230;;;:::o;3280:203:70:-;3405:4;3432:44;3452:7;3461:14;3432:19;:44::i;:::-;3425:51;3280:203;-1:-1:-1;;;3280:203:70:o;1319:109::-;1108:6:24;;-1:-1:-1;;;;;1108:6:24;719:10:37;1248:23:24;1240:68;;;;-1:-1:-1;;;1240:68:24;;;;;;;:::i;:::-;1394:27:70;;::::1;::::0;:16:::1;::::0;:27:::1;::::0;::::1;::::0;::::1;:::i;2191:235:30:-:0;2263:7;2298:16;;;:7;:16;;;;;;-1:-1:-1;;;;;2298:16:30;;2324:73;;;;-1:-1:-1;;;2324:73:30;;11132:2:82;2324:73:30;;;11114:21:82;11171:2;11151:18;;;11144:30;11210:34;11190:18;;;11183:62;-1:-1:-1;;;11261:18:82;;;11254:39;11310:19;;2324:73:30;10930:405:82;1929:205:30;2001:7;-1:-1:-1;;;;;2028:19:30;;2020:74;;;;-1:-1:-1;;;2020:74:30;;11542:2:82;2020:74:30;;;11524:21:82;11581:2;11561:18;;;11554:30;11620:34;11600:18;;;11593:62;-1:-1:-1;;;11671:18:82;;;11664:40;11721:19;;2020:74:30;11340:406:82;2020:74:30;-1:-1:-1;;;;;;2111:16:30;;;;;:9;:16;;;;;;;1929:205::o;1668:101:24:-;1108:6;;-1:-1:-1;;;;;1108:6:24;719:10:37;1248:23:24;1240:68;;;;-1:-1:-1;;;1240:68:24;;;;;;;:::i;:::-;1732:30:::1;1759:1;1732:18;:30::i;:::-;1668:101::o:0;1555:198:70:-;1108:6:24;;-1:-1:-1;;;;;1108:6:24;719:10:37;1248:23:24;1240:68;;;;-1:-1:-1;;;1240:68:24;;;;;;;:::i;:::-;1612:11:70::1;1626:13;1702:10:33::0;:17;;1615:111;1626:13:70::1;1612:27;;1649:6;1665:82;1681:1;1677;:5;1665:82;;;1703:33;1713:10;1725;1734:1:::0;1725:6;:10:::1;:::i;:::-;1703:9;:33::i;:::-;1684:3:::0;::::1;::::0;::::1;:::i;:::-;;;;1665:82;;2650:102:30::0;2706:13;2738:7;2731:14;;;;;:::i;4284:153::-;4378:52;719:10:37;4411:8:30;4421;4378:18;:52::i;1978:579:70:-;2044:10;2057:13;1702:10:33;:17;;1615:111;2057:13:70;2096:10;2088:19;;;;:7;:19;;;;;;2044:26;;-1:-1:-1;2088:19:70;;:28;2080:82;;;;-1:-1:-1;;;2080:82:70;;12358:2:82;2080:82:70;;;12340:21:82;12397:2;12377:18;;;12370:30;12436:34;12416:18;;;12409:62;-1:-1:-1;;;12487:18:82;;;12480:39;12536:19;;2080:82:70;12156:405:82;2080:82:70;2180:12;;-1:-1:-1;;;2180:12:70;;;;2172:50;;;;-1:-1:-1;;;2172:50:70;;12768:2:82;2172:50:70;;;12750:21:82;12807:2;12787:18;;;12780:30;12846:27;12826:18;;;12819:55;12891:18;;2172:50:70;12566:349:82;2172:50:70;785:4;2240:2;:15;2232:56;;;;-1:-1:-1;;;2232:56:70;;13122:2:82;2232:56:70;;;13104:21:82;13161:2;13141:18;;;13134:30;13200;13180:18;;;13173:58;13248:18;;2232:56:70;12920:352:82;2232:56:70;837:4;2306:14;;:32;2298:62;;;;-1:-1:-1;;;2298:62:70;;13479:2:82;2298:62:70;;;13461:21:82;13518:2;13498:18;;;13491:30;-1:-1:-1;;;13537:18:82;;;13530:47;13594:18;;2298:62:70;13277:341:82;2298:62:70;2378:47;2398:10;2410:14;2378:19;:47::i;:::-;2370:82;;;;-1:-1:-1;;;2370:82:70;;13825:2:82;2370:82:70;;;13807:21:82;13864:2;13844:18;;;13837:30;-1:-1:-1;;;13883:18:82;;;13876:52;13945:18;;2370:82:70;13623:346:82;2370:82:70;2471:10;2463:19;;;;:7;:19;;;;;:26;;-1:-1:-1;;2463:26:70;2485:4;2463:26;;;2499:25;;2521:2;2499:9;:25::i;:::-;2534:14;:16;;;:14;:16;;;:::i;:::-;;;;;;2034:523;1978:579;:::o;5368:320:30:-;5537:41;719:10:37;5570:7:30;5537:18;:41::i;:::-;5529:103;;;;-1:-1:-1;;;5529:103:30;;;;;;;:::i;:::-;5642:39;5656:4;5662:2;5666:7;5675:5;5642:13;:39::i;:::-;5368:320;;;;:::o;2739:187:70:-;1108:6:24;;-1:-1:-1;;;;;1108:6:24;719:10:37;1248:23:24;1240:68;;;;-1:-1:-1;;;1240:68:24;;;;;;;:::i;:::-;2845:20:70::1;:33:::0;;;2894:25:::1;::::0;2319::82;;;2894::70::1;::::0;2307:2:82;2292:18;2894:25:70::1;;;;;;;2739:187:::0;:::o;3601:337::-;7225:4:30;7248:16;;;:7;:16;;;;;;3674:13:70;;-1:-1:-1;;;;;7248:16:30;3699:76:70;;;;-1:-1:-1;;;3699:76:70;;14176:2:82;3699:76:70;;;14158:21:82;14215:2;14195:18;;;14188:30;14254:34;14234:18;;;14227:62;-1:-1:-1;;;14305:18:82;;;14298:45;14360:19;;3699:76:70;13974:411:82;3699:76:70;3786:21;3810:10;:8;:10::i;:::-;3786:34;;3862:1;3844:7;3838:21;:25;:93;;;;;;;;;;;;;;;;;3890:7;3899:25;3916:7;3899:16;:25::i;:::-;3873:52;;;;;;;;;:::i;:::-;;;;;;;;;;;;;3831:100;3601:337;-1:-1:-1;;;3601:337:70:o;2963:124::-;3029:7;3055:25;3216:20;;;3123:120;3055:25;3048:32;;2963:124;:::o;1918:198:24:-;1108:6;;-1:-1:-1;;;;;1108:6:24;719:10:37;1248:23:24;1240:68;;;;-1:-1:-1;;;1240:68:24;;;;;;;:::i;:::-;-1:-1:-1;;;;;2006:22:24;::::1;1998:73;;;::::0;-1:-1:-1;;;1998:73:24;;15067:2:82;1998:73:24::1;::::0;::::1;15049:21:82::0;15106:2;15086:18;;;15079:30;15145:34;15125:18;;;15118:62;-1:-1:-1;;;15196:18:82;;;15189:36;15242:19;;1998:73:24::1;14865:402:82::0;1998:73:24::1;2081:28;2100:8;2081:18;:28::i;:::-;1918:198:::0;:::o;990:222:33:-;1092:4;-1:-1:-1;;;;;;1115:50:33;;-1:-1:-1;;;1115:50:33;;:90;;;1169:36;1193:11;1169:23;:36::i;11169:171:30:-;11243:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;11243:29:30;-1:-1:-1;;;;;11243:29:30;;;;;;;;:24;;11296:23;11243:24;11296:14;:23::i;:::-;-1:-1:-1;;;;;11287:46:30;;;;;;;;;;;11169:171;;:::o;7443:344::-;7536:4;7248:16;;;:7;:16;;;;;;-1:-1:-1;;;;;7248:16:30;7552:73;;;;-1:-1:-1;;;7552:73:30;;15474:2:82;7552:73:30;;;15456:21:82;15513:2;15493:18;;;15486:30;15552:34;15532:18;;;15525:62;-1:-1:-1;;;15603:18:82;;;15596:42;15655:19;;7552:73:30;15272:408:82;7552:73:30;7635:13;7651:23;7666:7;7651:14;:23::i;:::-;7635:39;;7703:5;-1:-1:-1;;;;;7692:16:30;:7;-1:-1:-1;;;;;7692:16:30;;:52;;;-1:-1:-1;;;;;;4623:25:30;;;4600:4;4623:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;7712:32;7692:87;;;;7772:7;-1:-1:-1;;;;;7748:31:30;:20;7760:7;7748:11;:20::i;:::-;-1:-1:-1;;;;;7748:31:30;;7692:87;7684:96;7443:344;-1:-1:-1;;;;7443:344:30:o;10453:605::-;10607:4;-1:-1:-1;;;;;10580:31:30;:23;10595:7;10580:14;:23::i;:::-;-1:-1:-1;;;;;10580:31:30;;10572:81;;;;-1:-1:-1;;;10572:81:30;;15887:2:82;10572:81:30;;;15869:21:82;15926:2;15906:18;;;15899:30;15965:34;15945:18;;;15938:62;-1:-1:-1;;;16016:18:82;;;16009:35;16061:19;;10572:81:30;15685:401:82;10572:81:30;-1:-1:-1;;;;;10671:16:30;;10663:65;;;;-1:-1:-1;;;10663:65:30;;16293:2:82;10663:65:30;;;16275:21:82;16332:2;16312:18;;;16305:30;16371:34;16351:18;;;16344:62;-1:-1:-1;;;16422:18:82;;;16415:34;16466:19;;10663:65:30;16091:400:82;10663:65:30;10739:39;10760:4;10766:2;10770:7;10739:20;:39::i;:::-;10840:29;10857:1;10861:7;10840:8;:29::i;:::-;-1:-1:-1;;;;;10880:15:30;;;;;;:9;:15;;;;;:20;;10899:1;;10880:15;:20;;10899:1;;10880:20;:::i;:::-;;;;-1:-1:-1;;;;;;;10910:13:30;;;;;;:9;:13;;;;;:18;;10927:1;;10910:13;:18;;10927:1;;10910:18;:::i;:::-;;;;-1:-1:-1;;10938:16:30;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;10938:21:30;-1:-1:-1;;;;;10938:21:30;;;;;;;;;10975:27;;10938:16;;10975:27;;;;;;;3608:331;3538:401;;:::o;377:200:72:-;470:4;493:77;512:5;519:25;3216:20:70;;;3123:120;519:25:72;546:23;561:7;748:55;;-1:-1:-1;;773:4:72;18028:2:82;18024:15;;;18020:24;;748:55:72;;;18008:37:82;18079:15;;;18075:24;18061:12;;;18054:46;789:13:72;18116:12:82;;;18109:28;712:7:72;;18153:12:82;;748:55:72;;;;;;;;;;;;738:66;;;;;;731:73;;648:163;;;;546:23;493:18;:77::i;2270:187:24:-;2362:6;;;-1:-1:-1;;;;;2378:17:24;;;-1:-1:-1;;;;;;2378:17:24;;;;;;;2410:40;;2362:6;;;2378:17;2362:6;;2410:40;;2343:16;;2410:40;2333:124;2270:187;:::o;8117:108:30:-;8192:26;8202:2;8206:7;8192:26;;;;;;;;;;;;:9;:26::i;11475:307::-;11625:8;-1:-1:-1;;;;;11616:17:30;:5;-1:-1:-1;;;;;11616:17:30;;11608:55;;;;-1:-1:-1;;;11608:55:30;;16828:2:82;11608:55:30;;;16810:21:82;16867:2;16847:18;;;16840:30;16906:27;16886:18;;;16879:55;16951:18;;11608:55:30;16626:349:82;11608:55:30;-1:-1:-1;;;;;11673:25:30;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;11673:46:30;;;;;;;;;;11734:41;;540::82;;;11734::30;;513:18:82;11734:41:30;;;;;;;11475:307;;;:::o;6550:::-;6701:28;6711:4;6717:2;6721:7;6701:9;:28::i;:::-;6747:48;6770:4;6776:2;6780:7;6789:5;6747:22;:48::i;:::-;6739:111;;;;-1:-1:-1;;;6739:111:30;;;;;;;:::i;1434:115:70:-;1494:13;1526:16;1519:23;;;;;:::i;328:703:39:-;384:13;601:5;610:1;601:10;597:51;;-1:-1:-1;;627:10:39;;;;;;;;;;;;-1:-1:-1;;;627:10:39;;;;;328:703::o;597:51::-;672:5;657:12;711:75;718:9;;711:75;;743:8;;;;:::i;:::-;;-1:-1:-1;765:10:39;;-1:-1:-1;773:2:39;765:10;;:::i;:::-;;;711:75;;;795:19;827:6;817:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;817:17:39;;795:39;;844:150;851:10;;844:150;;877:11;887:1;877:11;;:::i;:::-;;-1:-1:-1;945:10:39;953:2;945:5;:10;:::i;:::-;932:24;;:2;:24;:::i;:::-;919:39;;902:6;909;902:14;;;;;;;;:::i;:::-;;;;:56;-1:-1:-1;;;;;902:56:39;;;;;;;;-1:-1:-1;972:11:39;981:2;972:11;;:::i;:::-;;;844:150;;1570:300:30;1672:4;-1:-1:-1;;;;;;1707:40:30;;-1:-1:-1;;;1707:40:30;;:104;;-1:-1:-1;;;;;;;1763:48:30;;-1:-1:-1;;;1763:48:30;1707:104;:156;;;-1:-1:-1;;;;;;;;;;937:40:41;;;1827:36:30;829:155:41;951:179:70;1078:45;1105:4;1111:2;1115:7;1078:26;:45::i;1154:184:40:-;1275:4;1327;1298:25;1311:5;1318:4;1298:12;:25::i;:::-;:33;;1154:184;-1:-1:-1;;;;1154:184:40:o;8446:311:30:-;8571:18;8577:2;8581:7;8571:5;:18::i;:::-;8620:54;8651:1;8655:2;8659:7;8668:5;8620:22;:54::i;:::-;8599:151;;;;-1:-1:-1;;;8599:151:30;;;;;;;:::i;12335:778::-;12485:4;-1:-1:-1;;;;;12505:13:30;;1465:19:36;:23;12501:606:30;;12540:72;;-1:-1:-1;;;12540:72:30;;-1:-1:-1;;;;;12540:36:30;;;;;:72;;719:10:37;;12591:4:30;;12597:7;;12606:5;;12540:72;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;12540:72:30;;;;;;;;-1:-1:-1;;12540:72:30;;;;;;;;;;;;:::i;:::-;;;12536:519;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12779:6;:13;12796:1;12779:18;12775:266;;12821:60;;-1:-1:-1;;;12821:60:30;;;;;;;:::i;12775:266::-;12993:6;12987:13;12978:6;12974:2;12970:15;12963:38;12536:519;-1:-1:-1;;;;;;12662:51:30;-1:-1:-1;;;12662:51:30;;-1:-1:-1;12655:58:30;;12501:606;-1:-1:-1;13092:4:30;12335:778;;;;;;:::o;2624:572:33:-;-1:-1:-1;;;;;2823:18:33;;2819:183;;2857:40;2889:7;4005:10;:17;;3978:24;;;;:15;:24;;;;;:44;;;4032:24;;;;;;;;;;;;3902:161;2857:40;2819:183;;;2926:2;-1:-1:-1;;;;;2918:10:33;:4;-1:-1:-1;;;;;2918:10:33;;2914:88;;2944:47;2977:4;2983:7;2944:32;:47::i;:::-;-1:-1:-1;;;;;3015:16:33;;3011:179;;3047:45;3084:7;3047:36;:45::i;3011:179::-;3119:4;-1:-1:-1;;;;;3113:10:33;:2;-1:-1:-1;;;;;3113:10:33;;3109:81;;3139:40;3167:2;3171:7;3139:27;:40::i;1689:662:40:-;1772:7;1814:4;1772:7;1828:488;1852:5;:12;1848:1;:16;1828:488;;;1885:20;1908:5;1914:1;1908:8;;;;;;;;:::i;:::-;;;;;;;1885:31;;1950:12;1934;:28;1930:376;;2425:13;2473:15;;;2508:4;2501:15;;;2554:4;2538:21;;2060:57;;1930:376;;;2425:13;2473:15;;;2508:4;2501:15;;;2554:4;2538:21;;2234:57;;1930:376;-1:-1:-1;1866:3:40;;;;:::i;:::-;;;;1828:488;;;-1:-1:-1;2332:12:40;1689:662;-1:-1:-1;;;1689:662:40:o;9079:427:30:-;-1:-1:-1;;;;;9158:16:30;;9150:61;;;;-1:-1:-1;;;9150:61:30;;19126:2:82;9150:61:30;;;19108:21:82;;;19145:18;;;19138:30;19204:34;19184:18;;;19177:62;19256:18;;9150:61:30;18924:356:82;9150:61:30;7225:4;7248:16;;;:7;:16;;;;;;-1:-1:-1;;;;;7248:16:30;:30;9221:58;;;;-1:-1:-1;;;9221:58:30;;19487:2:82;9221:58:30;;;19469:21:82;19526:2;19506:18;;;19499:30;19565;19545:18;;;19538:58;19613:18;;9221:58:30;19285:352:82;9221:58:30;9290:45;9319:1;9323:2;9327:7;9290:20;:45::i;:::-;-1:-1:-1;;;;;9346:13:30;;;;;;:9;:13;;;;;:18;;9363:1;;9346:13;:18;;9363:1;;9346:18;:::i;:::-;;;;-1:-1:-1;;9374:16:30;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;9374:21:30;-1:-1:-1;;;;;9374:21:30;;;;;;;;9411:33;;9374:16;;;9411:33;;9374:16;;9411:33;2658:37:70::1;2602:100;2563:139::o:0;4680:970:33:-;4942:22;4992:1;4967:22;4984:4;4967:16;:22::i;:::-;:26;;;;:::i;:::-;5003:18;5024:26;;;:17;:26;;;;;;4942:51;;-1:-1:-1;5154:28:33;;;5150:323;;-1:-1:-1;;;;;5220:18:33;;5198:19;5220:18;;;:12;:18;;;;;;;;:34;;;;;;;;;5269:30;;;;;;:44;;;5385:30;;:17;:30;;;;;:43;;;5150:323;-1:-1:-1;5566:26:33;;;;:17;:26;;;;;;;;5559:33;;;-1:-1:-1;;;;;5609:18:33;;;;;:12;:18;;;;;:34;;;;;;;5602:41;4680:970::o;5938:1061::-;6212:10;:17;6187:22;;6212:21;;6232:1;;6212:21;:::i;:::-;6243:18;6264:24;;;:15;:24;;;;;;6632:10;:26;;6187:46;;-1:-1:-1;6264:24:33;;6187:46;;6632:26;;;;;;:::i;:::-;;;;;;;;;6610:48;;6694:11;6669:10;6680;6669:22;;;;;;;;:::i;:::-;;;;;;;;;;;;:36;;;;6773:28;;;:15;:28;;;;;;;:41;;;6942:24;;;;;6935:31;6976:10;:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;6009:990;;;5938:1061;:::o;3490:217::-;3574:14;3591:20;3608:2;3591:16;:20::i;:::-;-1:-1:-1;;;;;3621:16:33;;;;;;;:12;:16;;;;;;;;:24;;;;;;;;:34;;;3665:26;;;:17;:26;;;;;;:35;;;;-1:-1:-1;3490:217:33:o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:131:82;-1:-1:-1;;;;;;88:32:82;;78:43;;68:71;;135:1;132;125:12;150:245;208:6;261:2;249:9;240:7;236:23;232:32;229:52;;;277:1;274;267:12;229:52;316:9;303:23;335:30;359:5;335:30;:::i;592:258::-;664:1;674:113;688:6;685:1;682:13;674:113;;;764:11;;;758:18;745:11;;;738:39;710:2;703:10;674:113;;;805:6;802:1;799:13;796:48;;;-1:-1:-1;;840:1:82;822:16;;815:27;592:258::o;855:::-;897:3;935:5;929:12;962:6;957:3;950:19;978:63;1034:6;1027:4;1022:3;1018:14;1011:4;1004:5;1000:16;978:63;:::i;:::-;1095:2;1074:15;-1:-1:-1;;1070:29:82;1061:39;;;;1102:4;1057:50;;855:258;-1:-1:-1;;855:258:82:o;1118:220::-;1267:2;1256:9;1249:21;1230:4;1287:45;1328:2;1317:9;1313:18;1305:6;1287:45;:::i;1343:180::-;1402:6;1455:2;1443:9;1434:7;1430:23;1426:32;1423:52;;;1471:1;1468;1461:12;1423:52;-1:-1:-1;1494:23:82;;1343:180;-1:-1:-1;1343:180:82:o;1736:173::-;1804:20;;-1:-1:-1;;;;;1853:31:82;;1843:42;;1833:70;;1899:1;1896;1889:12;1833:70;1736:173;;;:::o;1914:254::-;1982:6;1990;2043:2;2031:9;2022:7;2018:23;2014:32;2011:52;;;2059:1;2056;2049:12;2011:52;2082:29;2101:9;2082:29;:::i;:::-;2072:39;2158:2;2143:18;;;;2130:32;;-1:-1:-1;;;1914:254:82:o;2355:328::-;2432:6;2440;2448;2501:2;2489:9;2480:7;2476:23;2472:32;2469:52;;;2517:1;2514;2507:12;2469:52;2540:29;2559:9;2540:29;:::i;:::-;2530:39;;2588:38;2622:2;2611:9;2607:18;2588:38;:::i;:::-;2578:48;;2673:2;2662:9;2658:18;2645:32;2635:42;;2355:328;;;;;:::o;2688:160::-;2753:20;;2809:13;;2802:21;2792:32;;2782:60;;2838:1;2835;2828:12;2853:180;2909:6;2962:2;2950:9;2941:7;2937:23;2933:32;2930:52;;;2978:1;2975;2968:12;2930:52;3001:26;3017:9;3001:26;:::i;3038:127::-;3099:10;3094:3;3090:20;3087:1;3080:31;3130:4;3127:1;3120:15;3154:4;3151:1;3144:15;3170:275;3241:2;3235:9;3306:2;3287:13;;-1:-1:-1;;3283:27:82;3271:40;;3341:18;3326:34;;3362:22;;;3323:62;3320:88;;;3388:18;;:::i;:::-;3424:2;3417:22;3170:275;;-1:-1:-1;3170:275:82:o;3450:712::-;3504:5;3557:3;3550:4;3542:6;3538:17;3534:27;3524:55;;3575:1;3572;3565:12;3524:55;3611:6;3598:20;3637:4;3660:18;3656:2;3653:26;3650:52;;;3682:18;;:::i;:::-;3728:2;3725:1;3721:10;3751:28;3775:2;3771;3767:11;3751:28;:::i;:::-;3813:15;;;3883;;;3879:24;;;3844:12;;;;3915:15;;;3912:35;;;3943:1;3940;3933:12;3912:35;3979:2;3971:6;3967:15;3956:26;;3991:142;4007:6;4002:3;3999:15;3991:142;;;4073:17;;4061:30;;4024:12;;;;4111;;;;3991:142;;;4151:5;3450:712;-1:-1:-1;;;;;;;3450:712:82:o;4167:422::-;4260:6;4268;4321:2;4309:9;4300:7;4296:23;4292:32;4289:52;;;4337:1;4334;4327:12;4289:52;4360:29;4379:9;4360:29;:::i;:::-;4350:39;;4440:2;4429:9;4425:18;4412:32;4467:18;4459:6;4456:30;4453:50;;;4499:1;4496;4489:12;4453:50;4522:61;4575:7;4566:6;4555:9;4551:22;4522:61;:::i;:::-;4512:71;;;4167:422;;;;;:::o;4594:407::-;4659:5;4693:18;4685:6;4682:30;4679:56;;;4715:18;;:::i;:::-;4753:57;4798:2;4777:15;;-1:-1:-1;;4773:29:82;4804:4;4769:40;4753:57;:::i;:::-;4744:66;;4833:6;4826:5;4819:21;4873:3;4864:6;4859:3;4855:16;4852:25;4849:45;;;4890:1;4887;4880:12;4849:45;4939:6;4934:3;4927:4;4920:5;4916:16;4903:43;4993:1;4986:4;4977:6;4970:5;4966:18;4962:29;4955:40;4594:407;;;;;:::o;5006:451::-;5075:6;5128:2;5116:9;5107:7;5103:23;5099:32;5096:52;;;5144:1;5141;5134:12;5096:52;5184:9;5171:23;5217:18;5209:6;5206:30;5203:50;;;5249:1;5246;5239:12;5203:50;5272:22;;5325:4;5317:13;;5313:27;-1:-1:-1;5303:55:82;;5354:1;5351;5344:12;5303:55;5377:74;5443:7;5438:2;5425:16;5420:2;5416;5412:11;5377:74;:::i;5462:186::-;5521:6;5574:2;5562:9;5553:7;5549:23;5545:32;5542:52;;;5590:1;5587;5580:12;5542:52;5613:29;5632:9;5613:29;:::i;5653:254::-;5718:6;5726;5779:2;5767:9;5758:7;5754:23;5750:32;5747:52;;;5795:1;5792;5785:12;5747:52;5818:29;5837:9;5818:29;:::i;:::-;5808:39;;5866:35;5897:2;5886:9;5882:18;5866:35;:::i;:::-;5856:45;;5653:254;;;;;:::o;5912:348::-;5996:6;6049:2;6037:9;6028:7;6024:23;6020:32;6017:52;;;6065:1;6062;6055:12;6017:52;6105:9;6092:23;6138:18;6130:6;6127:30;6124:50;;;6170:1;6167;6160:12;6124:50;6193:61;6246:7;6237:6;6226:9;6222:22;6193:61;:::i;6265:667::-;6360:6;6368;6376;6384;6437:3;6425:9;6416:7;6412:23;6408:33;6405:53;;;6454:1;6451;6444:12;6405:53;6477:29;6496:9;6477:29;:::i;:::-;6467:39;;6525:38;6559:2;6548:9;6544:18;6525:38;:::i;:::-;6515:48;;6610:2;6599:9;6595:18;6582:32;6572:42;;6665:2;6654:9;6650:18;6637:32;6692:18;6684:6;6681:30;6678:50;;;6724:1;6721;6714:12;6678:50;6747:22;;6800:4;6792:13;;6788:27;-1:-1:-1;6778:55:82;;6829:1;6826;6819:12;6778:55;6852:74;6918:7;6913:2;6900:16;6895:2;6891;6887:11;6852:74;:::i;:::-;6842:84;;;6265:667;;;;;;;:::o;7122:260::-;7190:6;7198;7251:2;7239:9;7230:7;7226:23;7222:32;7219:52;;;7267:1;7264;7257:12;7219:52;7290:29;7309:9;7290:29;:::i;:::-;7280:39;;7338:38;7372:2;7361:9;7357:18;7338:38;:::i;7569:380::-;7648:1;7644:12;;;;7691;;;7712:61;;7766:4;7758:6;7754:17;7744:27;;7712:61;7819:2;7811:6;7808:14;7788:18;7785:38;7782:161;;7865:10;7860:3;7856:20;7853:1;7846:31;7900:4;7897:1;7890:15;7928:4;7925:1;7918:15;7782:161;;7569:380;;;:::o;9194:413::-;9396:2;9378:21;;;9435:2;9415:18;;;9408:30;9474:34;9469:2;9454:18;;9447:62;-1:-1:-1;;;9540:2:82;9525:18;;9518:47;9597:3;9582:19;;9194:413::o;9612:356::-;9814:2;9796:21;;;9833:18;;;9826:30;9892:34;9887:2;9872:18;;9865:62;9959:2;9944:18;;9612:356::o;10798:127::-;10859:10;10854:3;10850:20;10847:1;10840:31;10890:4;10887:1;10880:15;10914:4;10911:1;10904:15;11751:127;11812:10;11807:3;11803:20;11800:1;11793:31;11843:4;11840:1;11833:15;11867:4;11864:1;11857:15;11883:128;11923:3;11954:1;11950:6;11947:1;11944:13;11941:39;;;11960:18;;:::i;:::-;-1:-1:-1;11996:9:82;;11883:128::o;12016:135::-;12055:3;12076:17;;;12073:43;;12096:18;;:::i;:::-;-1:-1:-1;12143:1:82;12132:13;;12016:135::o;14390:470::-;14569:3;14607:6;14601:13;14623:53;14669:6;14664:3;14657:4;14649:6;14645:17;14623:53;:::i;:::-;14739:13;;14698:16;;;;14761:57;14739:13;14698:16;14795:4;14783:17;;14761:57;:::i;:::-;14834:20;;14390:470;-1:-1:-1;;;;14390:470:82:o;16496:125::-;16536:4;16564:1;16561;16558:8;16555:34;;;16569:18;;:::i;:::-;-1:-1:-1;16606:9:82;;16496:125::o;16980:414::-;17182:2;17164:21;;;17221:2;17201:18;;;17194:30;17260:34;17255:2;17240:18;;17233:62;-1:-1:-1;;;17326:2:82;17311:18;;17304:48;17384:3;17369:19;;16980:414::o;17399:127::-;17460:10;17455:3;17451:20;17448:1;17441:31;17491:4;17488:1;17481:15;17515:4;17512:1;17505:15;17531:120;17571:1;17597;17587:35;;17602:18;;:::i;:::-;-1:-1:-1;17636:9:82;;17531:120::o;17656:112::-;17688:1;17714;17704:35;;17719:18;;:::i;:::-;-1:-1:-1;17753:9:82;;17656:112::o;18176:489::-;-1:-1:-1;;;;;18445:15:82;;;18427:34;;18497:15;;18492:2;18477:18;;18470:43;18544:2;18529:18;;18522:34;;;18592:3;18587:2;18572:18;;18565:31;;;18370:4;;18613:46;;18639:19;;18631:6;18613:46;:::i;:::-;18605:54;18176:489;-1:-1:-1;;;;;;18176:489:82:o;18670:249::-;18739:6;18792:2;18780:9;18771:7;18767:23;18763:32;18760:52;;;18808:1;18805;18798:12;18760:52;18840:9;18834:16;18859:30;18883:5;18859:30;:::i;19642:127::-;19703:10;19698:3;19694:20;19691:1;19684:31;19734:4;19731:1;19724:15;19758:4;19755:1;19748:15
Swarm Source
ipfs://f996246cdd1aec30230a5aadf424675feeb82c40e5230faba3446518bfa106ad
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.