├── access ├── README.adoc ├── Ownable.sol ├── AccessControlEnumerable.sol └── AccessControl.sol ├── ERC721 ├── extensions │ ├── IERC721Metadata.sol │ ├── ERC721Burnable.sol │ ├── ERC721Pausable.sol │ ├── IERC721Enumerable.sol │ ├── ERC721URIStorage.sol │ └── ERC721Enumerable.sol ├── utils │ └── ERC721Holder.sol ├── IERC721Receiver.sol ├── presets │ └── ERC721PresetMinterPauserAutoId.sol ├── IERC721.sol └── ERC721.sol ├── utils ├── Context.sol ├── introspection │ ├── IERC165.sol │ └── ERC165.sol ├── Counters.sol ├── Strings.sol └── Address.sol └── security └── Pausable.sol /access/README.adoc: -------------------------------------------------------------------------------- 1 | = Access Control 2 | 3 | [.readme-notice] 4 | NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access 5 | 6 | This directory provides ways to restrict who can access the functions of a contract or when they can do it. 7 | 8 | - {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. 9 | - {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. 10 | 11 | == Authorization 12 | 13 | {{Ownable}} 14 | 15 | {{AccessControl}} 16 | 17 | {{AccessControlEnumerable}} 18 | -------------------------------------------------------------------------------- /ERC721/extensions/IERC721Metadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../IERC721.sol"; 6 | 7 | /** 8 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 9 | * @dev See https://eips.ethereum.org/EIPS/eip-721 10 | */ 11 | interface IERC721Metadata is IERC721 { 12 | /** 13 | * @dev Returns the token collection name. 14 | */ 15 | function name() external view returns (string memory); 16 | 17 | /** 18 | * @dev Returns the token collection symbol. 19 | */ 20 | function symbol() external view returns (string memory); 21 | 22 | /** 23 | * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. 24 | */ 25 | function tokenURI(uint256 tokenId) external view returns (string memory); 26 | } 27 | -------------------------------------------------------------------------------- /ERC721/utils/ERC721Holder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../IERC721Receiver.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC721Receiver} interface. 9 | * 10 | * Accepts all token transfers. 11 | * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. 12 | */ 13 | contract ERC721Holder is IERC721Receiver { 14 | /** 15 | * @dev See {IERC721Receiver-onERC721Received}. 16 | * 17 | * Always returns `IERC721Receiver.onERC721Received.selector`. 18 | */ 19 | function onERC721Received( 20 | address, 21 | address, 22 | uint256, 23 | bytes memory 24 | ) public virtual override returns (bytes4) { 25 | return this.onERC721Received.selector; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ERC721/extensions/ERC721Burnable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../ERC721.sol"; 6 | import "../../utils/Context.sol"; 7 | 8 | /** 9 | * @title ERC721 Burnable Token 10 | * @dev ERC721 Token that can be irreversibly burned (destroyed). 11 | */ 12 | abstract contract ERC721Burnable is Context, ERC721 { 13 | /** 14 | * @dev Burns `tokenId`. See {ERC721-_burn}. 15 | * 16 | * Requirements: 17 | * 18 | * - The caller must own `tokenId` or be an approved operator. 19 | */ 20 | function burn(uint256 tokenId) public virtual { 21 | //solhint-disable-next-line max-line-length 22 | require( 23 | _isApprovedOrOwner(_msgSender(), tokenId), 24 | "ERC721Burnable: caller is not owner nor approved" 25 | ); 26 | _burn(tokenId); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /utils/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /* 6 | * @dev Provides information about the current execution context, including the 7 | * sender of the transaction and its data. While these are generally available 8 | * via msg.sender and msg.data, they should not be accessed in such a direct 9 | * manner, since when dealing with meta-transactions the account sending and 10 | * paying for execution may not be the actual sender (as far as an application 11 | * is concerned). 12 | * 13 | * This contract is only required for intermediate, library-like contracts. 14 | */ 15 | abstract contract Context { 16 | function _msgSender() internal view virtual returns (address) { 17 | return msg.sender; 18 | } 19 | 20 | function _msgData() internal view virtual returns (bytes calldata) { 21 | return msg.data; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /utils/introspection/IERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Interface of the ERC165 standard, as defined in the 7 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 8 | * 9 | * Implementers can declare support of contract interfaces, which can then be 10 | * queried by others ({ERC165Checker}). 11 | * 12 | * For an implementation, see {ERC165}. 13 | */ 14 | interface IERC165 { 15 | /** 16 | * @dev Returns true if this contract implements the interface defined by 17 | * `interfaceId`. See the corresponding 18 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 19 | * to learn more about how these ids are created. 20 | * 21 | * This function call must use less than 30 000 gas. 22 | */ 23 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 24 | } 25 | -------------------------------------------------------------------------------- /ERC721/IERC721Receiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @title ERC721 token receiver interface 7 | * @dev Interface for any contract that wants to support safeTransfers 8 | * from ERC721 asset contracts. 9 | */ 10 | interface IERC721Receiver { 11 | /** 12 | * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} 13 | * by `operator` from `from`, this function is called. 14 | * 15 | * It must return its Solidity selector to confirm the token transfer. 16 | * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. 17 | * 18 | * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. 19 | */ 20 | function onERC721Received( 21 | address operator, 22 | address from, 23 | uint256 tokenId, 24 | bytes calldata data 25 | ) external returns (bytes4); 26 | } 27 | -------------------------------------------------------------------------------- /ERC721/extensions/ERC721Pausable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../ERC721.sol"; 6 | import "../../security/Pausable.sol"; 7 | 8 | /** 9 | * @dev ERC721 token with pausable token transfers, minting and burning. 10 | * 11 | * Useful for scenarios such as preventing trades until the end of an evaluation 12 | * period, or having an emergency switch for freezing all token transfers in the 13 | * event of a large bug. 14 | */ 15 | abstract contract ERC721Pausable is ERC721, Pausable { 16 | /** 17 | * @dev See {ERC721-_beforeTokenTransfer}. 18 | * 19 | * Requirements: 20 | * 21 | * - the contract must not be paused. 22 | */ 23 | function _beforeTokenTransfer( 24 | address from, 25 | address to, 26 | uint256 tokenId 27 | ) internal virtual override { 28 | super._beforeTokenTransfer(from, to, tokenId); 29 | 30 | require(!paused(), "ERC721Pausable: token transfer while paused"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /utils/introspection/ERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC165.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC165} interface. 9 | * 10 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 11 | * for the additional interface id that will be supported. For example: 12 | * 13 | * ```solidity 14 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 15 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 16 | * } 17 | * ``` 18 | * 19 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 20 | */ 21 | abstract contract ERC165 is IERC165 { 22 | /** 23 | * @dev See {IERC165-supportsInterface}. 24 | */ 25 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 26 | return interfaceId == type(IERC165).interfaceId; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ERC721/extensions/IERC721Enumerable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../IERC721.sol"; 6 | 7 | /** 8 | * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension 9 | * @dev See https://eips.ethereum.org/EIPS/eip-721 10 | */ 11 | interface IERC721Enumerable is IERC721 { 12 | /** 13 | * @dev Returns the total amount of tokens stored by the contract. 14 | */ 15 | function totalSupply() external view returns (uint256); 16 | 17 | /** 18 | * @dev Returns a token ID owned by `owner` at a given `index` of its token list. 19 | * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. 20 | */ 21 | function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); 22 | 23 | /** 24 | * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. 25 | * Use along with {totalSupply} to enumerate all tokens. 26 | */ 27 | function tokenByIndex(uint256 index) external view returns (uint256); 28 | } 29 | -------------------------------------------------------------------------------- /utils/Counters.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @title Counters 7 | * @author Matt Condon (@shrugs) 8 | * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number 9 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 10 | * 11 | * Include with `using Counters for Counters.Counter;` 12 | */ 13 | library Counters { 14 | struct Counter { 15 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 16 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 17 | // this feature: see https://github.com/ethereum/solidity/issues/4637 18 | uint256 _value; // default: 0 19 | } 20 | 21 | function current(Counter storage counter) internal view returns (uint256) { 22 | return counter._value; 23 | } 24 | 25 | function increment(Counter storage counter) internal { 26 | unchecked { 27 | counter._value += 1; 28 | } 29 | } 30 | 31 | function decrement(Counter storage counter) internal { 32 | uint256 value = counter._value; 33 | require(value > 0, "Counter: decrement overflow"); 34 | unchecked { 35 | counter._value = value - 1; 36 | } 37 | } 38 | 39 | function reset(Counter storage counter) internal { 40 | counter._value = 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ERC721/extensions/ERC721URIStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../ERC721.sol"; 6 | 7 | /** 8 | * @dev ERC721 token with storage based token URI management. 9 | */ 10 | abstract contract ERC721URIStorage is ERC721 { 11 | using Strings for uint256; 12 | 13 | // Optional mapping for token URIs 14 | mapping(uint256 => string) private _tokenURIs; 15 | 16 | /** 17 | * @dev See {IERC721Metadata-tokenURI}. 18 | */ 19 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 20 | require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token"); 21 | 22 | string memory _tokenURI = _tokenURIs[tokenId]; 23 | string memory base = _baseURI(); 24 | 25 | // If there is no base URI, return the token URI. 26 | if (bytes(base).length == 0) { 27 | return _tokenURI; 28 | } 29 | // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). 30 | if (bytes(_tokenURI).length > 0) { 31 | return string(abi.encodePacked(base, _tokenURI)); 32 | } 33 | 34 | return super.tokenURI(tokenId); 35 | } 36 | 37 | /** 38 | * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. 39 | * 40 | * Requirements: 41 | * 42 | * - `tokenId` must exist. 43 | */ 44 | function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { 45 | require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token"); 46 | _tokenURIs[tokenId] = _tokenURI; 47 | } 48 | 49 | /** 50 | * @dev Destroys `tokenId`. 51 | * The approval is cleared when the token is burned. 52 | * 53 | * Requirements: 54 | * 55 | * - `tokenId` must exist. 56 | * 57 | * Emits a {Transfer} event. 58 | */ 59 | function _burn(uint256 tokenId) internal virtual override { 60 | super._burn(tokenId); 61 | 62 | if (bytes(_tokenURIs[tokenId]).length != 0) { 63 | delete _tokenURIs[tokenId]; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /utils/Strings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev String operations. 7 | */ 8 | library Strings { 9 | bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; 10 | 11 | /** 12 | * @dev Converts a `uint256` to its ASCII `string` decimal representation. 13 | */ 14 | function toString(uint256 value) internal pure returns (string memory) { 15 | // Inspired by OraclizeAPI's implementation - MIT licence 16 | // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 17 | 18 | if (value == 0) { 19 | return "0"; 20 | } 21 | uint256 temp = value; 22 | uint256 digits; 23 | while (temp != 0) { 24 | digits++; 25 | temp /= 10; 26 | } 27 | bytes memory buffer = new bytes(digits); 28 | while (value != 0) { 29 | digits -= 1; 30 | buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); 31 | value /= 10; 32 | } 33 | return string(buffer); 34 | } 35 | 36 | /** 37 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 38 | */ 39 | function toHexString(uint256 value) internal pure returns (string memory) { 40 | if (value == 0) { 41 | return "0x00"; 42 | } 43 | uint256 temp = value; 44 | uint256 length = 0; 45 | while (temp != 0) { 46 | length++; 47 | temp >>= 8; 48 | } 49 | return toHexString(value, length); 50 | } 51 | 52 | /** 53 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 54 | */ 55 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 56 | bytes memory buffer = new bytes(2 * length + 2); 57 | buffer[0] = "0"; 58 | buffer[1] = "x"; 59 | for (uint256 i = 2 * length + 1; i > 1; --i) { 60 | buffer[i] = _HEX_SYMBOLS[value & 0xf]; 61 | value >>= 4; 62 | } 63 | require(value == 0, "Strings: hex length insufficient"); 64 | return string(buffer); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /access/Ownable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../utils/Context.sol"; 6 | 7 | /** 8 | * @dev Contract module which provides a basic access control mechanism, where 9 | * there is an account (an owner) that can be granted exclusive access to 10 | * specific functions. 11 | * 12 | * By default, the owner account will be the one that deploys the contract. This 13 | * can later be changed with {transferOwnership}. 14 | * 15 | * This module is used through inheritance. It will make available the modifier 16 | * `onlyOwner`, which can be applied to your functions to restrict their use to 17 | * the owner. 18 | */ 19 | abstract contract Ownable is Context { 20 | address private _owner; 21 | 22 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 23 | 24 | /** 25 | * @dev Initializes the contract setting the deployer as the initial owner. 26 | */ 27 | constructor() { 28 | address msgSender = _msgSender(); 29 | _owner = msgSender; 30 | emit OwnershipTransferred(address(0), msgSender); 31 | } 32 | 33 | /** 34 | * @dev Returns the address of the current owner. 35 | */ 36 | function owner() public view virtual returns (address) { 37 | return _owner; 38 | } 39 | 40 | /** 41 | * @dev Throws if called by any account other than the owner. 42 | */ 43 | modifier onlyOwner() { 44 | require(owner() == _msgSender(), "Ownable: caller is not the owner"); 45 | _; 46 | } 47 | 48 | /** 49 | * @dev Leaves the contract without owner. It will not be possible to call 50 | * `onlyOwner` functions anymore. Can only be called by the current owner. 51 | * 52 | * NOTE: Renouncing ownership will leave the contract without an owner, 53 | * thereby removing any functionality that is only available to the owner. 54 | */ 55 | function renounceOwnership() public virtual onlyOwner { 56 | emit OwnershipTransferred(_owner, address(0)); 57 | _owner = address(0); 58 | } 59 | 60 | /** 61 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 62 | * Can only be called by the current owner. 63 | */ 64 | function transferOwnership(address newOwner) public virtual onlyOwner { 65 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 66 | emit OwnershipTransferred(_owner, newOwner); 67 | _owner = newOwner; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /security/Pausable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../utils/Context.sol"; 6 | 7 | /** 8 | * @dev Contract module which allows children to implement an emergency stop 9 | * mechanism that can be triggered by an authorized account. 10 | * 11 | * This module is used through inheritance. It will make available the 12 | * modifiers `whenNotPaused` and `whenPaused`, which can be applied to 13 | * the functions of your contract. Note that they will not be pausable by 14 | * simply including this module, only once the modifiers are put in place. 15 | */ 16 | abstract contract Pausable is Context { 17 | /** 18 | * @dev Emitted when the pause is triggered by `account`. 19 | */ 20 | event Paused(address account); 21 | 22 | /** 23 | * @dev Emitted when the pause is lifted by `account`. 24 | */ 25 | event Unpaused(address account); 26 | 27 | bool private _paused; 28 | 29 | /** 30 | * @dev Initializes the contract in unpaused state. 31 | */ 32 | constructor() { 33 | _paused = false; 34 | } 35 | 36 | /** 37 | * @dev Returns true if the contract is paused, and false otherwise. 38 | */ 39 | function paused() public view virtual returns (bool) { 40 | return _paused; 41 | } 42 | 43 | /** 44 | * @dev Modifier to make a function callable only when the contract is not paused. 45 | * 46 | * Requirements: 47 | * 48 | * - The contract must not be paused. 49 | */ 50 | modifier whenNotPaused() { 51 | require(!paused(), "Pausable: paused"); 52 | _; 53 | } 54 | 55 | /** 56 | * @dev Modifier to make a function callable only when the contract is paused. 57 | * 58 | * Requirements: 59 | * 60 | * - The contract must be paused. 61 | */ 62 | modifier whenPaused() { 63 | require(paused(), "Pausable: not paused"); 64 | _; 65 | } 66 | 67 | /** 68 | * @dev Triggers stopped state. 69 | * 70 | * Requirements: 71 | * 72 | * - The contract must not be paused. 73 | */ 74 | function _pause() internal virtual whenNotPaused { 75 | _paused = true; 76 | emit Paused(_msgSender()); 77 | } 78 | 79 | /** 80 | * @dev Returns to normal state. 81 | * 82 | * Requirements: 83 | * 84 | * - The contract must be paused. 85 | */ 86 | function _unpause() internal virtual whenPaused { 87 | _paused = false; 88 | emit Unpaused(_msgSender()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /access/AccessControlEnumerable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./AccessControl.sol"; 6 | import "../utils/structs/EnumerableSet.sol"; 7 | 8 | /** 9 | * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. 10 | */ 11 | interface IAccessControlEnumerable { 12 | function getRoleMember(bytes32 role, uint256 index) external view returns (address); 13 | 14 | function getRoleMemberCount(bytes32 role) external view returns (uint256); 15 | } 16 | 17 | /** 18 | * @dev Extension of {AccessControl} that allows enumerating the members of each role. 19 | */ 20 | abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { 21 | using EnumerableSet for EnumerableSet.AddressSet; 22 | 23 | mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; 24 | 25 | /** 26 | * @dev See {IERC165-supportsInterface}. 27 | */ 28 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 29 | return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); 30 | } 31 | 32 | /** 33 | * @dev Returns one of the accounts that have `role`. `index` must be a 34 | * value between 0 and {getRoleMemberCount}, non-inclusive. 35 | * 36 | * Role bearers are not sorted in any particular way, and their ordering may 37 | * change at any point. 38 | * 39 | * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure 40 | * you perform all queries on the same block. See the following 41 | * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] 42 | * for more information. 43 | */ 44 | function getRoleMember(bytes32 role, uint256 index) public view override returns (address) { 45 | return _roleMembers[role].at(index); 46 | } 47 | 48 | /** 49 | * @dev Returns the number of accounts that have `role`. Can be used 50 | * together with {getRoleMember} to enumerate all bearers of a role. 51 | */ 52 | function getRoleMemberCount(bytes32 role) public view override returns (uint256) { 53 | return _roleMembers[role].length(); 54 | } 55 | 56 | /** 57 | * @dev Overload {grantRole} to track enumerable memberships 58 | */ 59 | function grantRole(bytes32 role, address account) public virtual override { 60 | super.grantRole(role, account); 61 | _roleMembers[role].add(account); 62 | } 63 | 64 | /** 65 | * @dev Overload {revokeRole} to track enumerable memberships 66 | */ 67 | function revokeRole(bytes32 role, address account) public virtual override { 68 | super.revokeRole(role, account); 69 | _roleMembers[role].remove(account); 70 | } 71 | 72 | /** 73 | * @dev Overload {renounceRole} to track enumerable memberships 74 | */ 75 | function renounceRole(bytes32 role, address account) public virtual override { 76 | super.renounceRole(role, account); 77 | _roleMembers[role].remove(account); 78 | } 79 | 80 | /** 81 | * @dev Overload {_setupRole} to track enumerable memberships 82 | */ 83 | function _setupRole(bytes32 role, address account) internal virtual override { 84 | super._setupRole(role, account); 85 | _roleMembers[role].add(account); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /ERC721/presets/ERC721PresetMinterPauserAutoId.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../ERC721.sol"; 6 | import "../extensions/ERC721Enumerable.sol"; 7 | import "../extensions/ERC721Burnable.sol"; 8 | import "../extensions/ERC721Pausable.sol"; 9 | import "../../access/AccessControlEnumerable.sol"; 10 | import "../../utils/Context.sol"; 11 | import "../../utils/Counters.sol"; 12 | 13 | /** 14 | * @dev {ERC721} token, including: 15 | * 16 | * - ability for holders to burn (destroy) their tokens 17 | * - a minter role that allows for token minting (creation) 18 | * - a pauser role that allows to stop all token transfers 19 | * - token ID and URI autogeneration 20 | * 21 | * This contract uses {AccessControl} to lock permissioned functions using the 22 | * different roles - head to its documentation for details. 23 | * 24 | * The account that deploys the contract will be granted the minter and pauser 25 | * roles, as well as the default admin role, which will let it grant both minter 26 | * and pauser roles to other accounts. 27 | */ 28 | contract ERC721PresetMinterPauserAutoId is 29 | Context, 30 | AccessControlEnumerable, 31 | ERC721Enumerable, 32 | ERC721Burnable, 33 | ERC721Pausable 34 | { 35 | using Counters for Counters.Counter; 36 | 37 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 38 | bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); 39 | 40 | Counters.Counter private _tokenIdTracker; 41 | 42 | string private _baseTokenURI; 43 | 44 | /** 45 | * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the 46 | * account that deploys the contract. 47 | * 48 | * Token URIs will be autogenerated based on `baseURI` and their token IDs. 49 | * See {ERC721-tokenURI}. 50 | */ 51 | constructor( 52 | string memory name, 53 | string memory symbol, 54 | string memory baseTokenURI 55 | ) ERC721(name, symbol) { 56 | _baseTokenURI = baseTokenURI; 57 | 58 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 59 | 60 | _setupRole(MINTER_ROLE, _msgSender()); 61 | _setupRole(PAUSER_ROLE, _msgSender()); 62 | } 63 | 64 | function _baseURI() internal view virtual override returns (string memory) { 65 | return _baseTokenURI; 66 | } 67 | 68 | /** 69 | * @dev Creates a new token for `to`. Its token ID will be automatically 70 | * assigned (and available on the emitted {IERC721-Transfer} event), and the token 71 | * URI autogenerated based on the base URI passed at construction. 72 | * 73 | * See {ERC721-_mint}. 74 | * 75 | * Requirements: 76 | * 77 | * - the caller must have the `MINTER_ROLE`. 78 | */ 79 | function mint(address to) public virtual { 80 | require( 81 | hasRole(MINTER_ROLE, _msgSender()), 82 | "ERC721PresetMinterPauserAutoId: must have minter role to mint" 83 | ); 84 | 85 | // We cannot just use balanceOf to create the new tokenId because tokens 86 | // can be burned (destroyed), so we need a separate counter. 87 | _mint(to, _tokenIdTracker.current()); 88 | _tokenIdTracker.increment(); 89 | } 90 | 91 | /** 92 | * @dev Pauses all token transfers. 93 | * 94 | * See {ERC721Pausable} and {Pausable-_pause}. 95 | * 96 | * Requirements: 97 | * 98 | * - the caller must have the `PAUSER_ROLE`. 99 | */ 100 | function pause() public virtual { 101 | require( 102 | hasRole(PAUSER_ROLE, _msgSender()), 103 | "ERC721PresetMinterPauserAutoId: must have pauser role to pause" 104 | ); 105 | _pause(); 106 | } 107 | 108 | /** 109 | * @dev Unpauses all token transfers. 110 | * 111 | * See {ERC721Pausable} and {Pausable-_unpause}. 112 | * 113 | * Requirements: 114 | * 115 | * - the caller must have the `PAUSER_ROLE`. 116 | */ 117 | function unpause() public virtual { 118 | require( 119 | hasRole(PAUSER_ROLE, _msgSender()), 120 | "ERC721PresetMinterPauserAutoId: must have pauser role to unpause" 121 | ); 122 | _unpause(); 123 | } 124 | 125 | function _beforeTokenTransfer( 126 | address from, 127 | address to, 128 | uint256 tokenId 129 | ) internal virtual override(ERC721, ERC721Enumerable, ERC721Pausable) { 130 | super._beforeTokenTransfer(from, to, tokenId); 131 | } 132 | 133 | /** 134 | * @dev See {IERC165-supportsInterface}. 135 | */ 136 | function supportsInterface(bytes4 interfaceId) 137 | public 138 | view 139 | virtual 140 | override(AccessControlEnumerable, ERC721, ERC721Enumerable) 141 | returns (bool) 142 | { 143 | return super.supportsInterface(interfaceId); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /ERC721/IERC721.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../utils/introspection/IERC165.sol"; 6 | 7 | /** 8 | * @dev Required interface of an ERC721 compliant contract. 9 | */ 10 | interface IERC721 is IERC165 { 11 | /** 12 | * @dev Emitted when `tokenId` token is transferred from `from` to `to`. 13 | */ 14 | event Transfer( 15 | address indexed from, 16 | address indexed to, 17 | uint256 indexed tokenId 18 | ); 19 | 20 | /** 21 | * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. 22 | */ 23 | event Approval( 24 | address indexed owner, 25 | address indexed approved, 26 | uint256 indexed tokenId 27 | ); 28 | 29 | /** 30 | * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. 31 | */ 32 | event ApprovalForAll( 33 | address indexed owner, 34 | address indexed operator, 35 | bool approved 36 | ); 37 | 38 | /** 39 | * @dev Returns the number of tokens in ``owner``'s account. 40 | */ 41 | function balanceOf(address owner) external view returns (uint256 balance); 42 | 43 | /** 44 | * @dev Returns the owner of the `tokenId` token. 45 | * 46 | * Requirements: 47 | * 48 | * - `tokenId` must exist. 49 | */ 50 | function ownerOf(uint256 tokenId) external view returns (address owner); 51 | 52 | /** 53 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 54 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 55 | * 56 | * Requirements: 57 | * 58 | * - `from` cannot be the zero address. 59 | * - `to` cannot be the zero address. 60 | * - `tokenId` token must exist and be owned by `from`. 61 | * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. 62 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 63 | * 64 | * Emits a {Transfer} event. 65 | */ 66 | function safeTransferFrom( 67 | address from, 68 | address to, 69 | uint256 tokenId 70 | ) external; 71 | 72 | /** 73 | * @dev Transfers `tokenId` token from `from` to `to`. 74 | * 75 | * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. 76 | * 77 | * Requirements: 78 | * 79 | * - `from` cannot be the zero address. 80 | * - `to` cannot be the zero address. 81 | * - `tokenId` token must be owned by `from`. 82 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 83 | * 84 | * Emits a {Transfer} event. 85 | */ 86 | function transferFrom( 87 | address from, 88 | address to, 89 | uint256 tokenId 90 | ) external; 91 | 92 | /** 93 | * @dev Gives permission to `to` to transfer `tokenId` token to another account. 94 | * The approval is cleared when the token is transferred. 95 | * 96 | * Only a single account can be approved at a time, so approving the zero address clears previous approvals. 97 | * 98 | * Requirements: 99 | * 100 | * - The caller must own the token or be an approved operator. 101 | * - `tokenId` must exist. 102 | * 103 | * Emits an {Approval} event. 104 | */ 105 | function approve(address to, uint256 tokenId) external; 106 | 107 | /** 108 | * @dev Returns the account approved for `tokenId` token. 109 | * 110 | * Requirements: 111 | * 112 | * - `tokenId` must exist. 113 | */ 114 | function getApproved(uint256 tokenId) 115 | external 116 | view 117 | returns (address operator); 118 | 119 | /** 120 | * @dev Approve or remove `operator` as an operator for the caller. 121 | * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. 122 | * 123 | * Requirements: 124 | * 125 | * - The `operator` cannot be the caller. 126 | * 127 | * Emits an {ApprovalForAll} event. 128 | */ 129 | function setApprovalForAll(address operator, bool _approved) external; 130 | 131 | /** 132 | * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. 133 | * 134 | * See {setApprovalForAll} 135 | */ 136 | function isApprovedForAll(address owner, address operator) 137 | external 138 | view 139 | returns (bool); 140 | 141 | /** 142 | * @dev Safely transfers `tokenId` token from `from` to `to`. 143 | * 144 | * Requirements: 145 | * 146 | * - `from` cannot be the zero address. 147 | * - `to` cannot be the zero address. 148 | * - `tokenId` token must exist and be owned by `from`. 149 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 150 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 151 | * 152 | * Emits a {Transfer} event. 153 | */ 154 | function safeTransferFrom( 155 | address from, 156 | address to, 157 | uint256 tokenId, 158 | bytes calldata data 159 | ) external; 160 | } 161 | -------------------------------------------------------------------------------- /ERC721/extensions/ERC721Enumerable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../ERC721.sol"; 6 | import "./IERC721Enumerable.sol"; 7 | 8 | /** 9 | * @dev This implements an optional extension of {ERC721} defined in the EIP that adds 10 | * enumerability of all the token ids in the contract as well as all token ids owned by each 11 | * account. 12 | */ 13 | abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { 14 | // Mapping from owner to list of owned token IDs 15 | mapping(address => mapping(uint256 => uint256)) private _ownedTokens; 16 | 17 | // Mapping from token ID to index of the owner tokens list 18 | mapping(uint256 => uint256) private _ownedTokensIndex; 19 | 20 | // Array with all token ids, used for enumeration 21 | uint256[] private _allTokens; 22 | 23 | // Mapping from token id to position in the allTokens array 24 | mapping(uint256 => uint256) private _allTokensIndex; 25 | 26 | /** 27 | * @dev See {IERC165-supportsInterface}. 28 | */ 29 | function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { 30 | return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); 31 | } 32 | 33 | /** 34 | * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. 35 | */ 36 | function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { 37 | require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); 38 | return _ownedTokens[owner][index]; 39 | } 40 | 41 | /** 42 | * @dev See {IERC721Enumerable-totalSupply}. 43 | */ 44 | function totalSupply() public view virtual override returns (uint256) { 45 | return _allTokens.length; 46 | } 47 | 48 | /** 49 | * @dev See {IERC721Enumerable-tokenByIndex}. 50 | */ 51 | function tokenByIndex(uint256 index) public view virtual override returns (uint256) { 52 | require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); 53 | return _allTokens[index]; 54 | } 55 | 56 | /** 57 | * @dev Hook that is called before any token transfer. This includes minting 58 | * and burning. 59 | * 60 | * Calling conditions: 61 | * 62 | * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be 63 | * transferred to `to`. 64 | * - When `from` is zero, `tokenId` will be minted for `to`. 65 | * - When `to` is zero, ``from``'s `tokenId` will be burned. 66 | * - `from` cannot be the zero address. 67 | * - `to` cannot be the zero address. 68 | * 69 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 70 | */ 71 | function _beforeTokenTransfer( 72 | address from, 73 | address to, 74 | uint256 tokenId 75 | ) internal virtual override { 76 | super._beforeTokenTransfer(from, to, tokenId); 77 | 78 | if (from == address(0)) { 79 | _addTokenToAllTokensEnumeration(tokenId); 80 | } else if (from != to) { 81 | _removeTokenFromOwnerEnumeration(from, tokenId); 82 | } 83 | if (to == address(0)) { 84 | _removeTokenFromAllTokensEnumeration(tokenId); 85 | } else if (to != from) { 86 | _addTokenToOwnerEnumeration(to, tokenId); 87 | } 88 | } 89 | 90 | /** 91 | * @dev Private function to add a token to this extension's ownership-tracking data structures. 92 | * @param to address representing the new owner of the given token ID 93 | * @param tokenId uint256 ID of the token to be added to the tokens list of the given address 94 | */ 95 | function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { 96 | uint256 length = ERC721.balanceOf(to); 97 | _ownedTokens[to][length] = tokenId; 98 | _ownedTokensIndex[tokenId] = length; 99 | } 100 | 101 | /** 102 | * @dev Private function to add a token to this extension's token tracking data structures. 103 | * @param tokenId uint256 ID of the token to be added to the tokens list 104 | */ 105 | function _addTokenToAllTokensEnumeration(uint256 tokenId) private { 106 | _allTokensIndex[tokenId] = _allTokens.length; 107 | _allTokens.push(tokenId); 108 | } 109 | 110 | /** 111 | * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that 112 | * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for 113 | * gas optimizations e.g. when performing a transfer operation (avoiding double writes). 114 | * This has O(1) time complexity, but alters the order of the _ownedTokens array. 115 | * @param from address representing the previous owner of the given token ID 116 | * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address 117 | */ 118 | function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { 119 | // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and 120 | // then delete the last slot (swap and pop). 121 | 122 | uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; 123 | uint256 tokenIndex = _ownedTokensIndex[tokenId]; 124 | 125 | // When the token to delete is the last token, the swap operation is unnecessary 126 | if (tokenIndex != lastTokenIndex) { 127 | uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; 128 | 129 | _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token 130 | _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index 131 | } 132 | 133 | // This also deletes the contents at the last position of the array 134 | delete _ownedTokensIndex[tokenId]; 135 | delete _ownedTokens[from][lastTokenIndex]; 136 | } 137 | 138 | /** 139 | * @dev Private function to remove a token from this extension's token tracking data structures. 140 | * This has O(1) time complexity, but alters the order of the _allTokens array. 141 | * @param tokenId uint256 ID of the token to be removed from the tokens list 142 | */ 143 | function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { 144 | // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and 145 | // then delete the last slot (swap and pop). 146 | 147 | uint256 lastTokenIndex = _allTokens.length - 1; 148 | uint256 tokenIndex = _allTokensIndex[tokenId]; 149 | 150 | // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so 151 | // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding 152 | // an 'if' statement (like in _removeTokenFromOwnerEnumeration) 153 | uint256 lastTokenId = _allTokens[lastTokenIndex]; 154 | 155 | _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token 156 | _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index 157 | 158 | // This also deletes the contents at the last position of the array 159 | delete _allTokensIndex[tokenId]; 160 | _allTokens.pop(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /utils/Address.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Collection of functions related to the address type 7 | */ 8 | library Address { 9 | /** 10 | * @dev Returns true if `account` is a contract. 11 | * 12 | * [IMPORTANT] 13 | * ==== 14 | * It is unsafe to assume that an address for which this function returns 15 | * false is an externally-owned account (EOA) and not a contract. 16 | * 17 | * Among others, `isContract` will return false for the following 18 | * types of addresses: 19 | * 20 | * - an externally-owned account 21 | * - a contract in construction 22 | * - an address where a contract will be created 23 | * - an address where a contract lived, but was destroyed 24 | * ==== 25 | */ 26 | function isContract(address account) internal view returns (bool) { 27 | // This method relies on extcodesize, which returns 0 for contracts in 28 | // construction, since the code is only stored at the end of the 29 | // constructor execution. 30 | 31 | uint256 size; 32 | assembly { 33 | size := extcodesize(account) 34 | } 35 | return size > 0; 36 | } 37 | 38 | /** 39 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 40 | * `recipient`, forwarding all available gas and reverting on errors. 41 | * 42 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 43 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 44 | * imposed by `transfer`, making them unable to receive funds via 45 | * `transfer`. {sendValue} removes this limitation. 46 | * 47 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 48 | * 49 | * IMPORTANT: because control is transferred to `recipient`, care must be 50 | * taken to not create reentrancy vulnerabilities. Consider using 51 | * {ReentrancyGuard} or the 52 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 53 | */ 54 | function sendValue(address payable recipient, uint256 amount) internal { 55 | require(address(this).balance >= amount, "Address: insufficient balance"); 56 | 57 | (bool success, ) = recipient.call{value: amount}(""); 58 | require(success, "Address: unable to send value, recipient may have reverted"); 59 | } 60 | 61 | /** 62 | * @dev Performs a Solidity function call using a low level `call`. A 63 | * plain `call` is an unsafe replacement for a function call: use this 64 | * function instead. 65 | * 66 | * If `target` reverts with a revert reason, it is bubbled up by this 67 | * function (like regular Solidity function calls). 68 | * 69 | * Returns the raw returned data. To convert to the expected return value, 70 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 71 | * 72 | * Requirements: 73 | * 74 | * - `target` must be a contract. 75 | * - calling `target` with `data` must not revert. 76 | * 77 | * _Available since v3.1._ 78 | */ 79 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 80 | return functionCall(target, data, "Address: low-level call failed"); 81 | } 82 | 83 | /** 84 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 85 | * `errorMessage` as a fallback revert reason when `target` reverts. 86 | * 87 | * _Available since v3.1._ 88 | */ 89 | function functionCall( 90 | address target, 91 | bytes memory data, 92 | string memory errorMessage 93 | ) internal returns (bytes memory) { 94 | return functionCallWithValue(target, data, 0, errorMessage); 95 | } 96 | 97 | /** 98 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 99 | * but also transferring `value` wei to `target`. 100 | * 101 | * Requirements: 102 | * 103 | * - the calling contract must have an ETH balance of at least `value`. 104 | * - the called Solidity function must be `payable`. 105 | * 106 | * _Available since v3.1._ 107 | */ 108 | function functionCallWithValue( 109 | address target, 110 | bytes memory data, 111 | uint256 value 112 | ) internal returns (bytes memory) { 113 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 114 | } 115 | 116 | /** 117 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 118 | * with `errorMessage` as a fallback revert reason when `target` reverts. 119 | * 120 | * _Available since v3.1._ 121 | */ 122 | function functionCallWithValue( 123 | address target, 124 | bytes memory data, 125 | uint256 value, 126 | string memory errorMessage 127 | ) internal returns (bytes memory) { 128 | require(address(this).balance >= value, "Address: insufficient balance for call"); 129 | require(isContract(target), "Address: call to non-contract"); 130 | 131 | (bool success, bytes memory returndata) = target.call{value: value}(data); 132 | return _verifyCallResult(success, returndata, errorMessage); 133 | } 134 | 135 | /** 136 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 137 | * but performing a static call. 138 | * 139 | * _Available since v3.3._ 140 | */ 141 | function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { 142 | return functionStaticCall(target, data, "Address: low-level static call failed"); 143 | } 144 | 145 | /** 146 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 147 | * but performing a static call. 148 | * 149 | * _Available since v3.3._ 150 | */ 151 | function functionStaticCall( 152 | address target, 153 | bytes memory data, 154 | string memory errorMessage 155 | ) internal view returns (bytes memory) { 156 | require(isContract(target), "Address: static call to non-contract"); 157 | 158 | (bool success, bytes memory returndata) = target.staticcall(data); 159 | return _verifyCallResult(success, returndata, errorMessage); 160 | } 161 | 162 | /** 163 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 164 | * but performing a delegate call. 165 | * 166 | * _Available since v3.4._ 167 | */ 168 | function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { 169 | return functionDelegateCall(target, data, "Address: low-level delegate call failed"); 170 | } 171 | 172 | /** 173 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 174 | * but performing a delegate call. 175 | * 176 | * _Available since v3.4._ 177 | */ 178 | function functionDelegateCall( 179 | address target, 180 | bytes memory data, 181 | string memory errorMessage 182 | ) internal returns (bytes memory) { 183 | require(isContract(target), "Address: delegate call to non-contract"); 184 | 185 | (bool success, bytes memory returndata) = target.delegatecall(data); 186 | return _verifyCallResult(success, returndata, errorMessage); 187 | } 188 | 189 | function _verifyCallResult( 190 | bool success, 191 | bytes memory returndata, 192 | string memory errorMessage 193 | ) private pure returns (bytes memory) { 194 | if (success) { 195 | return returndata; 196 | } else { 197 | // Look for revert reason and bubble it up if present 198 | if (returndata.length > 0) { 199 | // The easiest way to bubble the revert reason is using memory via assembly 200 | 201 | assembly { 202 | let returndata_size := mload(returndata) 203 | revert(add(32, returndata), returndata_size) 204 | } 205 | } else { 206 | revert(errorMessage); 207 | } 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /access/AccessControl.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../utils/Context.sol"; 6 | import "../utils/Strings.sol"; 7 | import "../utils/introspection/ERC165.sol"; 8 | 9 | /** 10 | * @dev External interface of AccessControl declared to support ERC165 detection. 11 | */ 12 | interface IAccessControl { 13 | function hasRole(bytes32 role, address account) external view returns (bool); 14 | 15 | function getRoleAdmin(bytes32 role) external view returns (bytes32); 16 | 17 | function grantRole(bytes32 role, address account) external; 18 | 19 | function revokeRole(bytes32 role, address account) external; 20 | 21 | function renounceRole(bytes32 role, address account) external; 22 | } 23 | 24 | /** 25 | * @dev Contract module that allows children to implement role-based access 26 | * control mechanisms. This is a lightweight version that doesn't allow enumerating role 27 | * members except through off-chain means by accessing the contract event logs. Some 28 | * applications may benefit from on-chain enumerability, for those cases see 29 | * {AccessControlEnumerable}. 30 | * 31 | * Roles are referred to by their `bytes32` identifier. These should be exposed 32 | * in the external API and be unique. The best way to achieve this is by 33 | * using `public constant` hash digests: 34 | * 35 | * ``` 36 | * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); 37 | * ``` 38 | * 39 | * Roles can be used to represent a set of permissions. To restrict access to a 40 | * function call, use {hasRole}: 41 | * 42 | * ``` 43 | * function foo() public { 44 | * require(hasRole(MY_ROLE, msg.sender)); 45 | * ... 46 | * } 47 | * ``` 48 | * 49 | * Roles can be granted and revoked dynamically via the {grantRole} and 50 | * {revokeRole} functions. Each role has an associated admin role, and only 51 | * accounts that have a role's admin role can call {grantRole} and {revokeRole}. 52 | * 53 | * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means 54 | * that only accounts with this role will be able to grant or revoke other 55 | * roles. More complex role relationships can be created by using 56 | * {_setRoleAdmin}. 57 | * 58 | * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to 59 | * grant and revoke this role. Extra precautions should be taken to secure 60 | * accounts that have been granted it. 61 | */ 62 | abstract contract AccessControl is Context, IAccessControl, ERC165 { 63 | struct RoleData { 64 | mapping(address => bool) members; 65 | bytes32 adminRole; 66 | } 67 | 68 | mapping(bytes32 => RoleData) private _roles; 69 | 70 | bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; 71 | 72 | /** 73 | * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` 74 | * 75 | * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite 76 | * {RoleAdminChanged} not being emitted signaling this. 77 | * 78 | * _Available since v3.1._ 79 | */ 80 | event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); 81 | 82 | /** 83 | * @dev Emitted when `account` is granted `role`. 84 | * 85 | * `sender` is the account that originated the contract call, an admin role 86 | * bearer except when using {_setupRole}. 87 | */ 88 | event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); 89 | 90 | /** 91 | * @dev Emitted when `account` is revoked `role`. 92 | * 93 | * `sender` is the account that originated the contract call: 94 | * - if using `revokeRole`, it is the admin role bearer 95 | * - if using `renounceRole`, it is the role bearer (i.e. `account`) 96 | */ 97 | event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); 98 | 99 | /** 100 | * @dev Modifier that checks that an account has a specific role. Reverts 101 | * with a standardized message including the required role. 102 | * 103 | * The format of the revert reason is given by the following regular expression: 104 | * 105 | * /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/ 106 | * 107 | * _Available since v4.1._ 108 | */ 109 | modifier onlyRole(bytes32 role) { 110 | _checkRole(role, _msgSender()); 111 | _; 112 | } 113 | 114 | /** 115 | * @dev See {IERC165-supportsInterface}. 116 | */ 117 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 118 | return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); 119 | } 120 | 121 | /** 122 | * @dev Returns `true` if `account` has been granted `role`. 123 | */ 124 | function hasRole(bytes32 role, address account) public view override returns (bool) { 125 | return _roles[role].members[account]; 126 | } 127 | 128 | /** 129 | * @dev Revert with a standard message if `account` is missing `role`. 130 | * 131 | * The format of the revert reason is given by the following regular expression: 132 | * 133 | * /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/ 134 | */ 135 | function _checkRole(bytes32 role, address account) internal view { 136 | if (!hasRole(role, account)) { 137 | revert( 138 | string( 139 | abi.encodePacked( 140 | "AccessControl: account ", 141 | Strings.toHexString(uint160(account), 20), 142 | " is missing role ", 143 | Strings.toHexString(uint256(role), 32) 144 | ) 145 | ) 146 | ); 147 | } 148 | } 149 | 150 | /** 151 | * @dev Returns the admin role that controls `role`. See {grantRole} and 152 | * {revokeRole}. 153 | * 154 | * To change a role's admin, use {_setRoleAdmin}. 155 | */ 156 | function getRoleAdmin(bytes32 role) public view override returns (bytes32) { 157 | return _roles[role].adminRole; 158 | } 159 | 160 | /** 161 | * @dev Grants `role` to `account`. 162 | * 163 | * If `account` had not been already granted `role`, emits a {RoleGranted} 164 | * event. 165 | * 166 | * Requirements: 167 | * 168 | * - the caller must have ``role``'s admin role. 169 | */ 170 | function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { 171 | _grantRole(role, account); 172 | } 173 | 174 | /** 175 | * @dev Revokes `role` from `account`. 176 | * 177 | * If `account` had been granted `role`, emits a {RoleRevoked} event. 178 | * 179 | * Requirements: 180 | * 181 | * - the caller must have ``role``'s admin role. 182 | */ 183 | function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { 184 | _revokeRole(role, account); 185 | } 186 | 187 | /** 188 | * @dev Revokes `role` from the calling account. 189 | * 190 | * Roles are often managed via {grantRole} and {revokeRole}: this function's 191 | * purpose is to provide a mechanism for accounts to lose their privileges 192 | * if they are compromised (such as when a trusted device is misplaced). 193 | * 194 | * If the calling account had been granted `role`, emits a {RoleRevoked} 195 | * event. 196 | * 197 | * Requirements: 198 | * 199 | * - the caller must be `account`. 200 | */ 201 | function renounceRole(bytes32 role, address account) public virtual override { 202 | require(account == _msgSender(), "AccessControl: can only renounce roles for self"); 203 | 204 | _revokeRole(role, account); 205 | } 206 | 207 | /** 208 | * @dev Grants `role` to `account`. 209 | * 210 | * If `account` had not been already granted `role`, emits a {RoleGranted} 211 | * event. Note that unlike {grantRole}, this function doesn't perform any 212 | * checks on the calling account. 213 | * 214 | * [WARNING] 215 | * ==== 216 | * This function should only be called from the constructor when setting 217 | * up the initial roles for the system. 218 | * 219 | * Using this function in any other way is effectively circumventing the admin 220 | * system imposed by {AccessControl}. 221 | * ==== 222 | */ 223 | function _setupRole(bytes32 role, address account) internal virtual { 224 | _grantRole(role, account); 225 | } 226 | 227 | /** 228 | * @dev Sets `adminRole` as ``role``'s admin role. 229 | * 230 | * Emits a {RoleAdminChanged} event. 231 | */ 232 | function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { 233 | emit RoleAdminChanged(role, getRoleAdmin(role), adminRole); 234 | _roles[role].adminRole = adminRole; 235 | } 236 | 237 | function _grantRole(bytes32 role, address account) private { 238 | if (!hasRole(role, account)) { 239 | _roles[role].members[account] = true; 240 | emit RoleGranted(role, account, _msgSender()); 241 | } 242 | } 243 | 244 | function _revokeRole(bytes32 role, address account) private { 245 | if (hasRole(role, account)) { 246 | _roles[role].members[account] = false; 247 | emit RoleRevoked(role, account, _msgSender()); 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /ERC721/ERC721.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC721.sol"; 6 | import "./IERC721Receiver.sol"; 7 | import "./extensions/IERC721Metadata.sol"; 8 | import "../utils/Address.sol"; 9 | import "../utils/Context.sol"; 10 | import "../utils/Strings.sol"; 11 | import "../utils/introspection/ERC165.sol"; 12 | 13 | /** 14 | * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including 15 | * the Metadata extension, but not including the Enumerable extension, which is available separately as 16 | * {ERC721Enumerable}. 17 | */ 18 | contract TheStripesNFT is Context, ERC165, IERC721, IERC721Metadata { 19 | using Address for address; 20 | using Strings for uint256; 21 | 22 | // Token name 23 | string private _name; 24 | 25 | // Token symbol 26 | string private _symbol; 27 | 28 | // Mapping from token ID to owner address 29 | mapping(uint256 => address) private _owners; 30 | 31 | // Mapping owner address to token count 32 | mapping(address => uint256) private _balances; 33 | 34 | // Mapping from token ID to approved address 35 | mapping(uint256 => address) private _tokenApprovals; 36 | 37 | // Mapping from owner to operator approvals 38 | mapping(address => mapping(address => bool)) private _operatorApprovals; 39 | 40 | /** 41 | * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. 42 | */ 43 | constructor(string memory name_, string memory symbol_) { 44 | _name = name_; 45 | _symbol = symbol_; 46 | } 47 | 48 | /** 49 | * @dev See {IERC165-supportsInterface}. 50 | */ 51 | function supportsInterface(bytes4 interfaceId) 52 | public 53 | view 54 | virtual 55 | override(ERC165, IERC165) 56 | returns (bool) 57 | { 58 | return 59 | interfaceId == type(IERC721).interfaceId || 60 | interfaceId == type(IERC721Metadata).interfaceId || 61 | super.supportsInterface(interfaceId); 62 | } 63 | 64 | /** 65 | * @dev See {IERC721-balanceOf}. 66 | */ 67 | function balanceOf(address owner) 68 | public 69 | view 70 | virtual 71 | override 72 | returns (uint256) 73 | { 74 | require( 75 | owner != address(0), 76 | "ERC721: balance query for the zero address" 77 | ); 78 | return _balances[owner]; 79 | } 80 | 81 | /** 82 | * @dev See {IERC721-ownerOf}. 83 | */ 84 | function ownerOf(uint256 tokenId) 85 | public 86 | view 87 | virtual 88 | override 89 | returns (address) 90 | { 91 | address owner = _owners[tokenId]; 92 | require( 93 | owner != address(0), 94 | "ERC721: owner query for nonexistent token" 95 | ); 96 | return owner; 97 | } 98 | 99 | /** 100 | * @dev See {IERC721Metadata-name}. 101 | */ 102 | function name() public view virtual override returns (string memory) { 103 | return _name; 104 | } 105 | 106 | /** 107 | * @dev See {IERC721Metadata-symbol}. 108 | */ 109 | function symbol() public view virtual override returns (string memory) { 110 | return _symbol; 111 | } 112 | 113 | /** 114 | * @dev See {IERC721Metadata-tokenURI}. 115 | */ 116 | function tokenURI(uint256 tokenId) 117 | public 118 | view 119 | virtual 120 | override 121 | returns (string memory) 122 | { 123 | require( 124 | _exists(tokenId), 125 | "ERC721Metadata: URI query for nonexistent token" 126 | ); 127 | 128 | string memory baseURI = _baseURI(); 129 | return 130 | bytes(baseURI).length > 0 131 | ? string(abi.encodePacked(baseURI, tokenId.toString())) 132 | : ""; 133 | } 134 | 135 | /** 136 | * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each 137 | * token will be the concatenation of the `baseURI` and the `tokenId`. Empty 138 | * by default, can be overriden in child contracts. 139 | */ 140 | function _baseURI() internal view virtual returns (string memory) { 141 | return ""; 142 | } 143 | 144 | /** 145 | * @dev See {IERC721-approve}. 146 | */ 147 | function approve(address to, uint256 tokenId) public virtual override { 148 | address owner = TheStripesNFT.ownerOf(tokenId); 149 | require(to != owner, "ERC721: approval to current owner"); 150 | 151 | require( 152 | _msgSender() == owner || isApprovedForAll(owner, _msgSender()), 153 | "ERC721: approve caller is not owner nor approved for all" 154 | ); 155 | 156 | _approve(to, tokenId); 157 | } 158 | 159 | /** 160 | * @dev See {IERC721-getApproved}. 161 | */ 162 | function getApproved(uint256 tokenId) 163 | public 164 | view 165 | virtual 166 | override 167 | returns (address) 168 | { 169 | require( 170 | _exists(tokenId), 171 | "ERC721: approved query for nonexistent token" 172 | ); 173 | 174 | return _tokenApprovals[tokenId]; 175 | } 176 | 177 | /** 178 | * @dev See {IERC721-setApprovalForAll}. 179 | */ 180 | function setApprovalForAll(address operator, bool approved) 181 | public 182 | virtual 183 | override 184 | { 185 | require(operator != _msgSender(), "ERC721: approve to caller"); 186 | 187 | _operatorApprovals[_msgSender()][operator] = approved; 188 | emit ApprovalForAll(_msgSender(), operator, approved); 189 | } 190 | 191 | /** 192 | * @dev See {IERC721-isApprovedForAll}. 193 | */ 194 | function isApprovedForAll(address owner, address operator) 195 | public 196 | view 197 | virtual 198 | override 199 | returns (bool) 200 | { 201 | return _operatorApprovals[owner][operator]; 202 | } 203 | 204 | /** 205 | * @dev See {IERC721-transferFrom}. 206 | */ 207 | function transferFrom( 208 | address from, 209 | address to, 210 | uint256 tokenId 211 | ) public virtual override { 212 | //solhint-disable-next-line max-line-length 213 | require( 214 | _isApprovedOrOwner(_msgSender(), tokenId), 215 | "ERC721: transfer caller is not owner nor approved" 216 | ); 217 | 218 | _transfer(from, to, tokenId); 219 | } 220 | 221 | /** 222 | * @dev See {IERC721-safeTransferFrom}. 223 | */ 224 | function safeTransferFrom( 225 | address from, 226 | address to, 227 | uint256 tokenId 228 | ) public virtual override { 229 | safeTransferFrom(from, to, tokenId, ""); 230 | } 231 | 232 | /** 233 | * @dev See {IERC721-safeTransferFrom}. 234 | */ 235 | function safeTransferFrom( 236 | address from, 237 | address to, 238 | uint256 tokenId, 239 | bytes memory _data 240 | ) public virtual override { 241 | require( 242 | _isApprovedOrOwner(_msgSender(), tokenId), 243 | "ERC721: transfer caller is not owner nor approved" 244 | ); 245 | _safeTransfer(from, to, tokenId, _data); 246 | } 247 | 248 | /** 249 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 250 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 251 | * 252 | * `_data` is additional data, it has no specified format and it is sent in call to `to`. 253 | * 254 | * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. 255 | * implement alternative mechanisms to perform token transfer, such as signature-based. 256 | * 257 | * Requirements: 258 | * 259 | * - `from` cannot be the zero address. 260 | * - `to` cannot be the zero address. 261 | * - `tokenId` token must exist and be owned by `from`. 262 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 263 | * 264 | * Emits a {Transfer} event. 265 | */ 266 | function _safeTransfer( 267 | address from, 268 | address to, 269 | uint256 tokenId, 270 | bytes memory _data 271 | ) internal virtual { 272 | _transfer(from, to, tokenId); 273 | require( 274 | _checkOnERC721Received(from, to, tokenId, _data), 275 | "ERC721: transfer to non ERC721Receiver implementer" 276 | ); 277 | } 278 | 279 | /** 280 | * @dev Returns whether `tokenId` exists. 281 | * 282 | * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. 283 | * 284 | * Tokens start existing when they are minted (`_mint`), 285 | * and stop existing when they are burned (`_burn`). 286 | */ 287 | function _exists(uint256 tokenId) internal view virtual returns (bool) { 288 | return _owners[tokenId] != address(0); 289 | } 290 | 291 | /** 292 | * @dev Returns whether `spender` is allowed to manage `tokenId`. 293 | * 294 | * Requirements: 295 | * 296 | * - `tokenId` must exist. 297 | */ 298 | function _isApprovedOrOwner(address spender, uint256 tokenId) 299 | internal 300 | view 301 | virtual 302 | returns (bool) 303 | { 304 | require( 305 | _exists(tokenId), 306 | "ERC721: operator query for nonexistent token" 307 | ); 308 | address owner = TheStripesNFT.ownerOf(tokenId); 309 | return (spender == owner || 310 | getApproved(tokenId) == spender || 311 | isApprovedForAll(owner, spender)); 312 | } 313 | 314 | /** 315 | * @dev Safely mints `tokenId` and transfers it to `to`. 316 | * 317 | * Requirements: 318 | * 319 | * - `tokenId` must not exist. 320 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 321 | * 322 | * Emits a {Transfer} event. 323 | */ 324 | function _safeMint(address to, uint256 tokenId) internal virtual { 325 | _safeMint(to, tokenId, ""); 326 | } 327 | 328 | /** 329 | * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is 330 | * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. 331 | */ 332 | function _safeMint( 333 | address to, 334 | uint256 tokenId, 335 | bytes memory _data 336 | ) internal virtual { 337 | _mint(to, tokenId); 338 | require( 339 | _checkOnERC721Received(address(0), to, tokenId, _data), 340 | "ERC721: transfer to non ERC721Receiver implementer" 341 | ); 342 | } 343 | 344 | /** 345 | * @dev Mints `tokenId` and transfers it to `to`. 346 | * 347 | * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible 348 | * 349 | * Requirements: 350 | * 351 | * - `tokenId` must not exist. 352 | * - `to` cannot be the zero address. 353 | * 354 | * Emits a {Transfer} event. 355 | */ 356 | function _mint(address to, uint256 tokenId) internal virtual { 357 | require(to != address(0), "ERC721: mint to the zero address"); 358 | require(!_exists(tokenId), "ERC721: token already minted"); 359 | 360 | _beforeTokenTransfer(address(0), to, tokenId); 361 | 362 | _balances[to] += 1; 363 | _owners[tokenId] = to; 364 | 365 | emit Transfer(address(0), to, tokenId); 366 | } 367 | 368 | /** 369 | * @dev Destroys `tokenId`. 370 | * The approval is cleared when the token is burned. 371 | * 372 | * Requirements: 373 | * 374 | * - `tokenId` must exist. 375 | * 376 | * Emits a {Transfer} event. 377 | */ 378 | function _burn(uint256 tokenId) internal virtual { 379 | address owner = TheStripesNFT.ownerOf(tokenId); 380 | 381 | _beforeTokenTransfer(owner, address(0), tokenId); 382 | 383 | // Clear approvals 384 | _approve(address(0), tokenId); 385 | 386 | _balances[owner] -= 1; 387 | delete _owners[tokenId]; 388 | 389 | emit Transfer(owner, address(0), tokenId); 390 | } 391 | 392 | /** 393 | * @dev Transfers `tokenId` from `from` to `to`. 394 | * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. 395 | * 396 | * Requirements: 397 | * 398 | * - `to` cannot be the zero address. 399 | * - `tokenId` token must be owned by `from`. 400 | * 401 | * Emits a {Transfer} event. 402 | */ 403 | function _transfer( 404 | address from, 405 | address to, 406 | uint256 tokenId 407 | ) internal virtual { 408 | require( 409 | TheStripesNFT.ownerOf(tokenId) == from, 410 | "TheStripesNFT: transfer of token that is not own" 411 | ); 412 | require( 413 | to != address(0), 414 | "TheStripesNFT: transfer to the zero address" 415 | ); 416 | 417 | _beforeTokenTransfer(from, to, tokenId); 418 | 419 | // Clear approvals from the previous owner 420 | _approve(address(0), tokenId); 421 | 422 | _balances[from] -= 1; 423 | _balances[to] += 1; 424 | _owners[tokenId] = to; 425 | 426 | emit Transfer(from, to, tokenId); 427 | } 428 | 429 | /** 430 | * @dev Approve `to` to operate on `tokenId` 431 | * 432 | * Emits a {Approval} event. 433 | */ 434 | function _approve(address to, uint256 tokenId) internal virtual { 435 | _tokenApprovals[tokenId] = to; 436 | emit Approval(TheStripesNFT.ownerOf(tokenId), to, tokenId); 437 | } 438 | 439 | /** 440 | * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. 441 | * The call is not executed if the target address is not a contract. 442 | * 443 | * @param from address representing the previous owner of the given token ID 444 | * @param to target address that will receive the tokens 445 | * @param tokenId uint256 ID of the token to be transferred 446 | * @param _data bytes optional data to send along with the call 447 | * @return bool whether the call correctly returned the expected magic value 448 | */ 449 | function _checkOnERC721Received( 450 | address from, 451 | address to, 452 | uint256 tokenId, 453 | bytes memory _data 454 | ) private returns (bool) { 455 | if (to.isContract()) { 456 | try 457 | IERC721Receiver(to).onERC721Received( 458 | _msgSender(), 459 | from, 460 | tokenId, 461 | _data 462 | ) 463 | returns (bytes4 retval) { 464 | return retval == IERC721Receiver(to).onERC721Received.selector; 465 | } catch (bytes memory reason) { 466 | if (reason.length == 0) { 467 | revert( 468 | "ERC721: transfer to non ERC721Receiver implementer" 469 | ); 470 | } else { 471 | assembly { 472 | revert(add(32, reason), mload(reason)) 473 | } 474 | } 475 | } 476 | } else { 477 | return true; 478 | } 479 | } 480 | 481 | /** 482 | * @dev Hook that is called before any token transfer. This includes minting 483 | * and burning. 484 | * 485 | * Calling conditions: 486 | * 487 | * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be 488 | * transferred to `to`. 489 | * - When `from` is zero, `tokenId` will be minted for `to`. 490 | * - When `to` is zero, ``from``'s `tokenId` will be burned. 491 | * - `from` and `to` are never both zero. 492 | * 493 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 494 | */ 495 | function _beforeTokenTransfer( 496 | address from, 497 | address to, 498 | uint256 tokenId 499 | ) internal virtual {} 500 | } 501 | --------------------------------------------------------------------------------