Transaction Hash:
Block:
12138471 at Mar-30-2021 04:29:31 AM +UTC
Transaction Fee:
0.016098966 ETH
$30.57
Gas Used:
157,833 Gas / 102 Gwei
Emitted Events:
130 |
Registry.Transfer( from=0x00000000...000000000, to=[Sender] 0x23b60995b9619edc040b2c1abce7ac4162432182, tokenId=104994600184009544906857847547128284616412723231877893473862360479994733935669 )
|
131 |
Registry.NewURI( tokenId=104994600184009544906857847547128284616412723231877893473862360479994733935669, uri=robertmarc.crypto )
|
132 |
Registry.Resolve( tokenId=104994600184009544906857847547128284616412723231877893473862360479994733935669, to=0xb66DcE2D...4B0ab2842 )
|
133 |
WhitelistedMinter.Relayed( sender=[Sender] 0x23b60995b9619edc040b2c1abce7ac4162432182, signer=0x2779D728...83523fe58, funcSig=System.Byte[], dataHash=1C264D6539D8BCCDCEE67A7F8E06F8D938126F2E23E553636C46F1E0019FDB66 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x23b60995...162432182 |
0.02687119 Eth
Nonce: 0
|
0.010772224 Eth
Nonce: 1
| 0.016098966 | ||
0xc8F595E2...25223b7C9
Miner
| (Miner: 0xc8F...7C9) | 5,492.950343398075817312 Eth | 5,492.966442364075817312 Eth | 0.016098966 | |
0xD1E5b0FF...08b9Dacbe |
Execution Trace
WhitelistedMinter.relay( data=0x3D7989FE00000000000000000000000023B60995B9619EDC040B2C1ABCE7AC4162432182000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000C000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000A726F626572746D6172630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, signature=0xB94C2D06E665F8C7DDA78BD73B9F7D4A2243D322A71732F8D51E6A7ABBBE62BC23097030995D1BB9B4CE590B66152FD7A4A7791854DDF576B150FCAAE9085B481B ) => ( 0x )
-
Null: 0x000...001.da0510d7( )
WhitelistedMinter.mintSLDToDefaultResolver( to=0x23b60995B9619EdC040b2c1ABcE7Ac4162432182, label=robertmarc, keys=[], values=[] )
MintingController.mintSLDWithResolver( to=0x23b60995B9619EdC040b2c1ABcE7Ac4162432182, label=robertmarc, resolver=0xb66DcE2DA6afAAa98F2013446dBCB0f4B0ab2842 )
-
Registry.STATICCALL( )
-
Registry.controlledMintChild( to=0x23b60995B9619EdC040b2c1ABcE7Ac4162432182, tokenId=6915554286656091279949062454670022140884697215296220624394276976218079984239, label=robertmarc )
-
Registry.STATICCALL( )
-
Registry.childIdOf( tokenId=6915554286656091279949062454670022140884697215296220624394276976218079984239, label=robertmarc ) => ( 104994600184009544906857847547128284616412723231877893473862360479994733935669 )
-
Registry.controlledResolveTo( to=0xb66DcE2DA6afAAa98F2013446dBCB0f4B0ab2842, tokenId=104994600184009544906857847547128284616412723231877893473862360479994733935669 )
-
relay[WhitelistedMinter (ln:2002)]
verifySigner[WhitelistedMinter (ln:2004)]
recover[WhitelistedMinter (ln:2038)]
toEthSignedMessageHash[WhitelistedMinter (ln:2038)]
isWhitelisted[WhitelistedMinter (ln:2042)]
verifyCall[WhitelistedMinter (ln:2006)]
call[WhitelistedMinter (ln:2009)]
Relayed[WhitelistedMinter (ln:2020)]
File 1 of 3: WhitelistedMinter
File 2 of 3: Registry
File 3 of 3: MintingController
pragma solidity 0.5.12; pragma experimental ABIEncoderV2; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * (.note) This call _does not revert_ if the signature is invalid, or * if the signer is otherwise unable to be retrieved. In those scenarios, * the zero address is returned. * * (.warning) `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise) * be too long), and then calling `toEthSignedMessageHash` on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { return (address(0)); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return address(0); } if (v != 27 && v != 28) { return address(0); } // If the signature is valid (and not malleable), return the signer address return ecrecover(hash, v, r, s); } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * [`eth_sign`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign) * JSON-RPC method. * * See `recover`. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } } /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev Give an account access to this role. */ function add(Role storage role, address account) internal { require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } /** * @dev Remove an account's access to this role. */ function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } /** * @dev Check if an account has this role. * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } } /** * @title WhitelistAdminRole * @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts. */ contract WhitelistAdminRole { using Roles for Roles.Role; event WhitelistAdminAdded(address indexed account); event WhitelistAdminRemoved(address indexed account); Roles.Role private _whitelistAdmins; constructor () internal { _addWhitelistAdmin(msg.sender); } modifier onlyWhitelistAdmin() { require(isWhitelistAdmin(msg.sender), "WhitelistAdminRole: caller does not have the WhitelistAdmin role"); _; } function isWhitelistAdmin(address account) public view returns (bool) { return _whitelistAdmins.has(account); } function addWhitelistAdmin(address account) public onlyWhitelistAdmin { _addWhitelistAdmin(account); } function renounceWhitelistAdmin() public { _removeWhitelistAdmin(msg.sender); } function _addWhitelistAdmin(address account) internal { _whitelistAdmins.add(account); emit WhitelistAdminAdded(account); } function _removeWhitelistAdmin(address account) internal { _whitelistAdmins.remove(account); emit WhitelistAdminRemoved(account); } } /** * @title WhitelistedRole * @dev Whitelisted accounts have been approved by a WhitelistAdmin to perform certain actions (e.g. participate in a * crowdsale). This role is special in that the only accounts that can add it are WhitelistAdmins (who can also remove * it), and not Whitelisteds themselves. */ contract WhitelistedRole is WhitelistAdminRole { using Roles for Roles.Role; event WhitelistedAdded(address indexed account); event WhitelistedRemoved(address indexed account); Roles.Role private _whitelisteds; modifier onlyWhitelisted() { require(isWhitelisted(msg.sender), "WhitelistedRole: caller does not have the Whitelisted role"); _; } function isWhitelisted(address account) public view returns (bool) { return _whitelisteds.has(account); } function addWhitelisted(address account) public onlyWhitelistAdmin { _addWhitelisted(account); } function removeWhitelisted(address account) public onlyWhitelistAdmin { _removeWhitelisted(account); } function renounceWhitelisted() public { _removeWhitelisted(msg.sender); } function _addWhitelisted(address account) internal { _whitelisteds.add(account); emit WhitelistedAdded(account); } function _removeWhitelisted(address account) internal { _whitelisteds.remove(account); emit WhitelistedRemoved(account); } } /** * @title BulkWhitelistedRole * @dev a Whitelist role defined using the Open Zeppelin Role system with the addition of bulkAddWhitelisted and * bulkRemoveWhitelisted. * @dev Whitelisted accounts have been approved by a WhitelistAdmin to perform certain actions (e.g. participate in a * crowdsale). This role is special in that the only accounts that can add it are WhitelistAdmins (who can also remove * it), and not Whitelisteds themselves. */ contract BulkWhitelistedRole is WhitelistedRole { function bulkAddWhitelisted(address[] memory accounts) public onlyWhitelistAdmin { for (uint256 index = 0; index < accounts.length; index++) { _addWhitelisted(accounts[index]); } } function bulkRemoveWhitelisted(address[] memory accounts) public onlyWhitelistAdmin { for (uint256 index = 0; index < accounts.length; index++) { _removeWhitelisted(accounts[index]); } } } interface IMintingController { /** * @dev Minter function that mints a Second Level Domain (SLD). * @param to address to mint the new SLD to. * @param label SLD label to mint. */ function mintSLD(address to, string calldata label) external; /** * @dev Minter function that safely mints a Second Level Domain (SLD). * Implements a ERC721Reciever check unlike mintSLD. * @param to address to mint the new SLD to. * @param label SLD label to mint. */ function safeMintSLD(address to, string calldata label) external; /** * @dev Minter function that safely mints a Second Level Domain (SLD). * Implements a ERC721Reciever check unlike mintSLD. * @param to address to mint the new SLD to. * @param label SLD label to mint. * @param _data bytes data to send along with a safe transfer check */ function safeMintSLD(address to, string calldata label, bytes calldata _data) external; } contract MinterRole { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; constructor () internal { _addMinter(msg.sender); } modifier onlyMinter() { require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role"); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(msg.sender); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } } /** * @dev Interface of the ERC165 standard, as defined in the * [EIP](https://eips.ethereum.org/EIPS/eip-165). * * 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 * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * 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); } /** * @dev Required interface of an ERC721 compliant contract. */ contract IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of NFTs in `owner`'s account. */ function balanceOf(address owner) public view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) public view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either `approve` or `setApproveForAll`. */ function safeTransferFrom(address from, address to, uint256 tokenId) public; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either `approve` or `setApproveForAll`. */ function transferFrom(address from, address to, uint256 tokenId) public; function approve(address to, uint256 tokenId) public; function getApproved(uint256 tokenId) public view returns (address operator); function setApprovalForAll(address operator, bool _approved) public; function isApprovedForAll(address owner, address operator) public view returns (bool); function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; } /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ contract IERC721Metadata is IERC721 { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); } contract IRegistry is IERC721Metadata { event NewURI(uint256 indexed tokenId, string uri); event NewURIPrefix(string prefix); event Resolve(uint256 indexed tokenId, address indexed to); event Sync(address indexed resolver, uint256 indexed updateId, uint256 indexed tokenId); /** * @dev Controlled function to set the token URI Prefix for all tokens. * @param prefix string URI to assign */ function controlledSetTokenURIPrefix(string calldata prefix) external; /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool); /** * @dev Mints a new a child token. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token not exist. * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the parent token * @param label subdomain label of the child token ID */ function mintChild(address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled function to mint a given token ID. * Requires the msg.sender to be controller. * Requires the token ID to not exist. * @param to address the given token ID will be minted to * @param label string that is a subdomain * @param tokenId uint256 ID of the parent token */ function controlledMintChild(address to, uint256 tokenId, string calldata label) external; /** * @dev Transfers the ownership of a child token ID to another address. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param label subdomain label of the child token ID */ function transferFromChild(address from, address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled function to transfers the ownership of a token ID to * another address. * Requires the msg.sender to be controller. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function controlledTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Safely transfers the ownership of a child token ID to another address. * Calculates child token ID using a namehash function. * Implements a ERC721Reciever check unlike transferFromChild. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 parent ID of the token to be transferred * @param label subdomain label of the child token ID * @param _data bytes data to send along with a safe transfer check */ function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label, bytes calldata _data) external; /// Shorthand for calling the above ^^^ safeTransferFromChild function with an empty _data parameter. Similar to ERC721.safeTransferFrom. function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled frunction to safely transfers the ownership of a token ID * to another address. * Implements a ERC721Reciever check unlike controlledSafeTransferFrom. * Requires the msg.sender to be controller. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 parent ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function controlledSafeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external; /** * @dev Burns a child token ID. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param tokenId uint256 ID of the token to be transferred * @param label subdomain label of the child token ID */ function burnChild(uint256 tokenId, string calldata label) external; /** * @dev Controlled function to burn a given token ID. * Requires the msg.sender to be controller. * Requires the token already exist. * @param tokenId uint256 ID of the token to be burned */ function controlledBurn(uint256 tokenId) external; /** * @dev Sets the resolver of a given token ID to another address. * Requires the msg.sender to be the owner, approved, or operator. * @param to address the given token ID will resolve to * @param tokenId uint256 ID of the token to be transferred */ function resolveTo(address to, uint256 tokenId) external; /** * @dev Gets the resolver of the specified token ID. * @param tokenId uint256 ID of the token to query the resolver of * @return address currently marked as the resolver of the given token ID */ function resolverOf(uint256 tokenId) external view returns (address); /** * @dev Controlled function to sets the resolver of a given token ID. * Requires the msg.sender to be controller. * @param to address the given token ID will resolve to * @param tokenId uint256 ID of the token to be transferred */ function controlledResolveTo(address to, uint256 tokenId) external; /** * @dev Provides child token (subdomain) of provided tokenId. * @param tokenId uint256 ID of the token * @param label label of subdomain (for `aaa.bbb.crypto` it will be `aaa`) */ function childIdOf(uint256 tokenId, string calldata label) external pure returns (uint256); /** * @dev Transfer domain ownership without resetting domain records. * @param to address of new domain owner * @param tokenId uint256 ID of the token to be transferred */ function setOwner(address to, uint256 tokenId) external; } /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ contract IERC721Receiver { /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient * after a `safeTransfer`. This function MUST return the function selector, * otherwise the caller will revert the transaction. The selector to be * returned can be obtained as `this.onERC721Received.selector`. This * function MAY throw to revert and reject the transfer. * Note: the ERC721 contract address is always the message sender. * @param operator The address which called `safeTransferFrom` function * @param from The address which previously owned the token * @param tokenId The NFT identifier which is being transferred * @param data Additional data with no specified format * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4); } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } /** * @dev Collection of functions related to the address type, */ library Address { /** * @dev Returns true if `account` is a contract. * * This test is non-exhaustive, and there may be false-negatives: during the * execution of a contract's constructor, its address will be reported as * not containing a contract. * * > It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } /** * @dev Implementation of the `IERC165` interface. * * Contracts may inherit from this and call `_registerInterface` to declare * their support of an interface. */ contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See `IERC165.supportsInterface`. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See `IERC165.supportsInterface`. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is ERC165, IERC721 { using SafeMath for uint256; using Address for address; using Counters for Counters.Counter; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // Mapping from token ID to owner mapping (uint256 => address) private _tokenOwner; // Mapping from token ID to approved address mapping (uint256 => address) private _tokenApprovals; // Mapping from owner to number of owned token mapping (address => Counters.Counter) private _ownedTokensCount; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; /* * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ * 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd */ bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; constructor () public { // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_ERC721); } /** * @dev Gets the balance of the specified address. * @param owner address to query the balance of * @return uint256 representing the amount owned by the passed address */ function balanceOf(address owner) public view returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _ownedTokensCount[owner].current(); } /** * @dev Gets the owner of the specified token ID. * @param tokenId uint256 ID of the token to query the owner of * @return address currently marked as the owner of the given token ID */ function ownerOf(uint256 tokenId) public view returns (address) { address owner = _tokenOwner[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev Approves another address to transfer the given token ID * The zero address indicates there is no approved address. * There can only be one approved address per token at a given time. * Can only be called by the token owner or an approved operator. * @param to address to be approved for the given token ID * @param tokenId uint256 ID of the token to be approved */ function approve(address to, uint256 tokenId) public { address owner = ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "ERC721: approve caller is not owner nor approved for all" ); _tokenApprovals[tokenId] = to; emit Approval(owner, to, tokenId); } /** * @dev Gets the approved address for a token ID, or zero if no address set * Reverts if the token ID does not exist. * @param tokenId uint256 ID of the token to query the approval of * @return address currently approved for the given token ID */ function getApproved(uint256 tokenId) public view returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev Sets or unsets the approval of a given operator * An operator is allowed to transfer all tokens of the sender on their behalf. * @param to operator address to set the approval * @param approved representing the status of the approval to be set */ function setApprovalForAll(address to, bool approved) public { require(to != msg.sender, "ERC721: approve to caller"); _operatorApprovals[msg.sender][to] = approved; emit ApprovalForAll(msg.sender, to, approved); } /** * @dev Tells whether an operator is approved by a given owner. * @param owner owner address which you want to query the approval of * @param operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ function isApprovedForAll(address owner, address operator) public view returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev Transfers the ownership of a given token ID to another address. * Usage of this method is discouraged, use `safeTransferFrom` whenever possible. * Requires the msg.sender to be the owner, approved, or operator. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function transferFrom(address from, address to, uint256 tokenId) public { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved"); _transferFrom(from, to, tokenId); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function safeTransferFrom(address from, address to, uint256 tokenId) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether the specified token exists. * @param tokenId uint256 ID of the token to query the existence of * @return bool whether the token exists */ function _exists(uint256 tokenId) internal view returns (bool) { address owner = _tokenOwner[tokenId]; return owner != address(0); } /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Internal function to mint a new token. * Reverts if the given token ID already exists. * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted */ function _mint(address to, uint256 tokenId) internal { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _tokenOwner[tokenId] = to; _ownedTokensCount[to].increment(); emit Transfer(address(0), to, tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * Deprecated, use _burn(uint256) instead. * @param owner owner of the token to burn * @param tokenId uint256 ID of the token being burned */ function _burn(address owner, uint256 tokenId) internal { require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own"); _clearApproval(tokenId); _ownedTokensCount[owner].decrement(); _tokenOwner[tokenId] = address(0); emit Transfer(owner, address(0), tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * @param tokenId uint256 ID of the token being burned */ function _burn(uint256 tokenId) internal { _burn(ownerOf(tokenId), tokenId); } /** * @dev Internal function to transfer ownership of a given token ID to another address. * As opposed to transferFrom, this imposes no restrictions on msg.sender. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function _transferFrom(address from, address to, uint256 tokenId) internal { require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _clearApproval(tokenId); _ownedTokensCount[from].decrement(); _ownedTokensCount[to].increment(); _tokenOwner[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @dev Internal function to invoke `onERC721Received` on a target address. * The call is not executed if the target address is not a contract. * * This function is deprecated. * @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) internal returns (bool) { if (!to.isContract()) { return true; } bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data); return (retval == _ERC721_RECEIVED); } /** * @dev Private function to clear current approval of a given token ID. * @param tokenId uint256 ID of the token to be transferred */ function _clearApproval(uint256 tokenId) private { if (_tokenApprovals[tokenId] != address(0)) { _tokenApprovals[tokenId] = address(0); } } } /** * @title ERC721 Burnable Token * @dev ERC721 Token that can be irreversibly burned (destroyed). */ contract ERC721Burnable is ERC721 { /** * @dev Burns a specific ERC721 token. * @param tokenId uint256 id of the ERC721 token to be burned. */ function burn(uint256 tokenId) public { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); } } // solium-disable error-reason /** * @title ControllerRole * @dev An Controller role defined using the Open Zeppelin Role system. */ contract ControllerRole { using Roles for Roles.Role; // NOTE: Commented out standard Role events to save gas. // event ControllerAdded(address indexed account); // event ControllerRemoved(address indexed account); Roles.Role private _controllers; constructor () public { _addController(msg.sender); } modifier onlyController() { require(isController(msg.sender)); _; } function isController(address account) public view returns (bool) { return _controllers.has(account); } function addController(address account) public onlyController { _addController(account); } function renounceController() public { _removeController(msg.sender); } function _addController(address account) internal { _controllers.add(account); // emit ControllerAdded(account); } function _removeController(address account) internal { _controllers.remove(account); // emit ControllerRemoved(account); } } // solium-disable no-empty-blocks,error-reason /** * @title Registry * @dev An ERC721 Token see https://eips.ethereum.org/EIPS/eip-721. With * additional functions so other trusted contracts to interact with the tokens. */ contract Registry is IRegistry, ControllerRole, ERC721Burnable { // Optional mapping for token URIs mapping(uint256 => string) internal _tokenURIs; string internal _prefix; // Mapping from token ID to resolver address mapping (uint256 => address) internal _tokenResolvers; // uint256(keccak256(abi.encodePacked(uint256(0x0), keccak256(abi.encodePacked("crypto"))))) uint256 private constant _CRYPTO_HASH = 0x0f4a10a4f46c288cea365fcf45cccf0e9d901b945b9829ccdb54c10dc3cb7a6f; modifier onlyApprovedOrOwner(uint256 tokenId) { require(_isApprovedOrOwner(msg.sender, tokenId)); _; } constructor () public { _mint(address(0xdead), _CRYPTO_HASH); // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(0x5b5e139f); // ERC721 Metadata Interface _tokenURIs[root()] = "crypto"; emit NewURI(root(), "crypto"); } /// ERC721 Metadata extension function name() external view returns (string memory) { return ".crypto"; } function symbol() external view returns (string memory) { return "UD"; } function tokenURI(uint256 tokenId) external view returns (string memory) { require(_exists(tokenId)); return string(abi.encodePacked(_prefix, _tokenURIs[tokenId])); } function controlledSetTokenURIPrefix(string calldata prefix) external onlyController { _prefix = prefix; emit NewURIPrefix(prefix); } /// Ownership function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool) { return _isApprovedOrOwner(spender, tokenId); } /// Registry Constants function root() public pure returns (uint256) { return _CRYPTO_HASH; } function childIdOf(uint256 tokenId, string calldata label) external pure returns (uint256) { return _childId(tokenId, label); } /// Minting function mintChild(address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _mintChild(to, tokenId, label); } function controlledMintChild(address to, uint256 tokenId, string calldata label) external onlyController { _mintChild(to, tokenId, label); } function safeMintChild(address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _safeMintChild(to, tokenId, label, ""); } function safeMintChild(address to, uint256 tokenId, string calldata label, bytes calldata _data) external onlyApprovedOrOwner(tokenId) { _safeMintChild(to, tokenId, label, _data); } function controlledSafeMintChild(address to, uint256 tokenId, string calldata label, bytes calldata _data) external onlyController { _safeMintChild(to, tokenId, label, _data); } /// Transfering function setOwner(address to, uint256 tokenId) external onlyApprovedOrOwner(tokenId) { super._transferFrom(ownerOf(tokenId), to, tokenId); } function transferFromChild(address from, address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _transferFrom(from, to, _childId(tokenId, label)); } function controlledTransferFrom(address from, address to, uint256 tokenId) external onlyController { _transferFrom(from, to, tokenId); } function safeTransferFromChild( address from, address to, uint256 tokenId, string memory label, bytes memory _data ) public onlyApprovedOrOwner(tokenId) { uint256 childId = _childId(tokenId, label); _transferFrom(from, to, childId); require(_checkOnERC721Received(from, to, childId, _data)); } function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label) external { safeTransferFromChild(from, to, tokenId, label, ""); } function controlledSafeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external onlyController { _transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data)); } /// Burning function burnChild(uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _burn(_childId(tokenId, label)); } function controlledBurn(uint256 tokenId) external onlyController { _burn(tokenId); } /// Resolution function resolverOf(uint256 tokenId) external view returns (address) { address resolver = _tokenResolvers[tokenId]; require(resolver != address(0)); return resolver; } function resolveTo(address to, uint256 tokenId) external onlyApprovedOrOwner(tokenId) { _resolveTo(to, tokenId); } function controlledResolveTo(address to, uint256 tokenId) external onlyController { _resolveTo(to, tokenId); } function sync(uint256 tokenId, uint256 updateId) external { require(_tokenResolvers[tokenId] == msg.sender); emit Sync(msg.sender, updateId, tokenId); } /// Internal function _childId(uint256 tokenId, string memory label) internal pure returns (uint256) { require(bytes(label).length != 0); return uint256(keccak256(abi.encodePacked(tokenId, keccak256(abi.encodePacked(label))))); } function _mintChild(address to, uint256 tokenId, string memory label) internal { uint256 childId = _childId(tokenId, label); _mint(to, childId); require(bytes(label).length != 0); require(_exists(childId)); bytes memory domain = abi.encodePacked(label, ".", _tokenURIs[tokenId]); _tokenURIs[childId] = string(domain); emit NewURI(childId, string(domain)); } function _safeMintChild(address to, uint256 tokenId, string memory label, bytes memory _data) internal { _mintChild(to, tokenId, label); require(_checkOnERC721Received(address(0), to, _childId(tokenId, label), _data)); } function _transferFrom(address from, address to, uint256 tokenId) internal { super._transferFrom(from, to, tokenId); // Clear resolver (if any) if (_tokenResolvers[tokenId] != address(0x0)) { delete _tokenResolvers[tokenId]; } } function _burn(uint256 tokenId) internal { super._burn(tokenId); // Clear resolver (if any) if (_tokenResolvers[tokenId] != address(0x0)) { delete _tokenResolvers[tokenId]; } // Clear metadata (if any) if (bytes(_tokenURIs[tokenId]).length != 0) { delete _tokenURIs[tokenId]; } } function _resolveTo(address to, uint256 tokenId) internal { require(_exists(tokenId)); emit Resolve(tokenId, to); _tokenResolvers[tokenId] = to; } } /** * @title MintingController * @dev Defines the functions for distribution of Second Level Domains (SLD)s. */ contract MintingController is IMintingController, MinterRole { Registry internal _registry; constructor (Registry registry) public { _registry = registry; } function registry() external view returns (address) { return address(_registry); } function mintSLD(address to, string memory label) public onlyMinter { _registry.controlledMintChild(to, _registry.root(), label); } function safeMintSLD(address to, string calldata label) external { safeMintSLD(to, label, ""); } function safeMintSLD(address to, string memory label, bytes memory _data) public onlyMinter { _registry.controlledSafeMintChild(to, _registry.root(), label, _data); } function mintSLDWithResolver(address to, string memory label, address resolver) public onlyMinter { _registry.controlledMintChild(to, _registry.root(), label); _registry.controlledResolveTo(resolver, _registry.childIdOf(_registry.root(), label)); } function safeMintSLDWithResolver(address to, string calldata label, address resolver) external { safeMintSLD(to, label, ""); _registry.controlledResolveTo(resolver, _registry.childIdOf(_registry.root(), label)); } function safeMintSLDWithResolver(address to, string calldata label, address resolver, bytes calldata _data) external { safeMintSLD(to, label, _data); _registry.controlledResolveTo(resolver, _registry.childIdOf(_registry.root(), label)); } } // solium-disable error-reason contract SignatureUtil { using ECDSA for bytes32; // Mapping from owner to a nonce mapping (uint256 => uint256) internal _nonces; Registry internal _registry; constructor(Registry registry) public { _registry = registry; } function registry() external view returns (address) { return address(_registry); } /** * @dev Gets the nonce of the specified address. * @param tokenId token ID for nonce query * @return nonce of the given address */ function nonceOf(uint256 tokenId) external view returns (uint256) { return _nonces[tokenId]; } function _validate(bytes32 hash, uint256 tokenId, bytes memory signature) internal { uint256 nonce = _nonces[tokenId]; address signer = keccak256(abi.encodePacked(hash, address(this), nonce)).toEthSignedMessageHash().recover(signature); require( signer != address(0) && _registry.isApprovedOrOwner( signer, tokenId ), "INVALID_SIGNATURE" ); _nonces[tokenId] += 1; } } contract IResolver { /** * @dev Reset all domain records and set new ones * @param keys New record keys * @param values New record values * @param tokenId ERC-721 token id of the domain */ function reconfigure(string[] memory keys, string[] memory values, uint256 tokenId) public; /** * @dev Set or update domain records * @param keys New record keys * @param values New record values * @param tokenId ERC-721 token id of the domain */ function setMany(string[] memory keys, string[] memory values, uint256 tokenId) public; /** * @dev Function to set record. * @param key The key set the value of. * @param value The value to set key to. * @param tokenId ERC-721 token id to set. */ function set(string calldata key, string calldata value, uint256 tokenId) external; /** * @dev Function to reset all existing records on a domain. * @param tokenId ERC-721 token id to set. */ function reset(uint256 tokenId) external; } interface IResolverReader { /** * @dev Gets the nonce of the specified address. * @param tokenId token ID for nonce query * @return nonce of the given address */ function nonceOf(uint256 tokenId) external view returns (uint256); /** * @return registry address */ function registry() external view returns (address); /** * @dev Function to get record. * @param key The key to query the value of. * @param tokenId The token id to fetch. * @return The value string. */ function get(string calldata key, uint256 tokenId) external view returns (string memory); /** * @dev Function to get multiple record. * @param keys The keys to query the value of. * @param tokenId The token id to fetch. * @return The values. */ function getMany(string[] calldata keys, uint256 tokenId) external view returns (string[] memory); /** * @dev Function get value by provied key hash. Keys hashes can be found in Sync event emitted by Registry.sol contract. * @param keyHash The key to query the value of. * @param tokenId The token id to set. * @return Key and value. */ function getByHash(uint256 keyHash, uint256 tokenId) external view returns (string memory key, string memory value); /** * @dev Function get values by provied key hashes. Keys hashes can be found in Sync event emitted by Registry.sol contract. * @param keyHashes The key to query the value of. * @param tokenId The token id to set. * @return Keys and values. */ function getManyByHash(uint256[] calldata keyHashes, uint256 tokenId) external view returns (string[] memory keys, string[] memory values); } // solium-disable error-reason contract Resolver is IResolverReader, SignatureUtil, IResolver { event Set(uint256 indexed tokenId, string indexed keyIndex, string indexed valueIndex, string key, string value); event NewKey(uint256 indexed tokenId, string indexed keyIndex, string key); event ResetRecords(uint256 indexed tokenId); // Mapping from token ID to preset id to key to value mapping (uint256 => mapping (uint256 => mapping (string => string))) internal _records; // Mapping from token ID to current preset id mapping (uint256 => uint256) _tokenPresets; // All keys that were set mapping (uint256 => string) _hashedKeys; MintingController internal _mintingController; constructor(Registry registry, MintingController mintingController) public SignatureUtil(registry) { require(address(registry) == mintingController.registry()); _mintingController = mintingController; } /** * @dev Throws if called when not the resolver. */ modifier whenResolver(uint256 tokenId) { require(address(this) == _registry.resolverOf(tokenId), "RESOLVER_DETACHED_FROM_DOMAIN"); _; } modifier whenApprovedOrOwner(uint256 tokenId) { require(_registry.isApprovedOrOwner(msg.sender, tokenId), "SENDER_IS_NOT_APPROVED_OR_OWNER"); _; } function reset(uint256 tokenId) external whenApprovedOrOwner(tokenId) { _setPreset(now, tokenId); } function resetFor(uint256 tokenId, bytes calldata signature) external { _validate(keccak256(abi.encodeWithSelector(this.reset.selector, tokenId)), tokenId, signature); _setPreset(now, tokenId); } /** * @dev Function to get record. * @param key The key to query the value of. * @param tokenId The token id to fetch. * @return The value string. */ function get(string memory key, uint256 tokenId) public view whenResolver(tokenId) returns (string memory) { return _records[tokenId][_tokenPresets[tokenId]][key]; } /** * @dev Function to get key by provided hash. Keys hashes can be found in Sync event emitted by Registry.sol contract. * @param keyHash The key to query the value of. * @return The key string. */ function hashToKey(uint256 keyHash) public view returns (string memory) { return _hashedKeys[keyHash]; } /** * @dev Function to get keys by provided key hashes. Keys hashes can be found in Sync event emitted by Registry.sol contract. * @param hashes The key to query the value of. * @return Keys */ function hashesToKeys(uint256[] memory hashes) public view returns (string[] memory) { uint256 keyCount = hashes.length; string[] memory values = new string[](keyCount); for (uint256 i = 0; i < keyCount; i++) { values[i] = hashToKey(hashes[i]); } return values; } /** * @dev Function get value by provied key hash. Keys hashes can be found in Sync event emitted by Registry.sol contract. * @param keyHash The key to query the value of. * @param tokenId The token id to set. * @return Key and value. */ function getByHash(uint256 keyHash, uint256 tokenId) public view whenResolver(tokenId) returns (string memory key, string memory value) { key = hashToKey(keyHash); value = get(key, tokenId); } /** * @dev Function get values by provied key hashes. Keys hashes can be found in Sync event emitted by Registry.sol contract. * @param keyHashes The key to query the value of. * @param tokenId The token id to set. * @return Keys and values. */ function getManyByHash( uint256[] memory keyHashes, uint256 tokenId ) public view whenResolver(tokenId) returns (string[] memory keys, string[] memory values) { uint256 keyCount = keyHashes.length; keys = new string[](keyCount); values = new string[](keyCount); for (uint256 i = 0; i < keyCount; i++) { (keys[i], values[i]) = getByHash(keyHashes[i], tokenId); } } function preconfigure( string[] memory keys, string[] memory values, uint256 tokenId ) public { require(_mintingController.isMinter(msg.sender), "SENDER_IS_NOT_MINTER"); _setMany(_tokenPresets[tokenId], keys, values, tokenId); } /** * @dev Function to set record. * @param key The key set the value of. * @param value The value to set key to. * @param tokenId The token id to set. */ function set(string calldata key, string calldata value, uint256 tokenId) external whenApprovedOrOwner(tokenId) { _set(_tokenPresets[tokenId], key, value, tokenId); } /** * @dev Function to set record on behalf of an address. * @param key The key set the value of. * @param value The value to set key to. * @param tokenId The token id to set. * @param signature The signature to verify the transaction with. */ function setFor( string calldata key, string calldata value, uint256 tokenId, bytes calldata signature ) external { _validate(keccak256(abi.encodeWithSelector(this.set.selector, key, value, tokenId)), tokenId, signature); _set(_tokenPresets[tokenId], key, value, tokenId); } /** * @dev Function to get multiple record. * @param keys The keys to query the value of. * @param tokenId The token id to fetch. * @return The values. */ function getMany(string[] calldata keys, uint256 tokenId) external view whenResolver(tokenId) returns (string[] memory) { uint256 keyCount = keys.length; string[] memory values = new string[](keyCount); uint256 preset = _tokenPresets[tokenId]; for (uint256 i = 0; i < keyCount; i++) { values[i] = _records[tokenId][preset][keys[i]]; } return values; } function setMany( string[] memory keys, string[] memory values, uint256 tokenId ) public whenApprovedOrOwner(tokenId) { _setMany(_tokenPresets[tokenId], keys, values, tokenId); } /** * @dev Function to set record on behalf of an address. * @param keys The keys set the values of. * @param values The values to set keys to. * @param tokenId The token id to set. * @param signature The signature to verify the transaction with. */ function setManyFor( string[] memory keys, string[] memory values, uint256 tokenId, bytes memory signature ) public { _validate(keccak256(abi.encodeWithSelector(this.setMany.selector, keys, values, tokenId)), tokenId, signature); _setMany(_tokenPresets[tokenId], keys, values, tokenId); } /** * @dev Function to reset all domain records and set new ones. * @param keys records keys. * @param values records values. * @param tokenId domain token id. */ function reconfigure(string[] memory keys, string[] memory values, uint256 tokenId) public whenApprovedOrOwner(tokenId) { _reconfigure(keys, values, tokenId); } /** * @dev Delegated version of reconfigure() function. * @param keys records keys. * @param values records values. * @param tokenId domain token id. * @param signature user signature. */ function reconfigureFor( string[] memory keys, string[] memory values, uint256 tokenId, bytes memory signature ) public { _validate(keccak256(abi.encodeWithSelector(this.reconfigure.selector, keys, values, tokenId)), tokenId, signature); _reconfigure(keys, values, tokenId); } // reset records function _setPreset(uint256 presetId, uint256 tokenId) internal { _tokenPresets[tokenId] = presetId; _registry.sync(tokenId, 0); // notify registry that domain records were reset emit ResetRecords(tokenId); } /** * @dev Internal function to to set record. As opposed to set, this imposes no restrictions on msg.sender. * @param preset preset to set key/values on * @param key key of record to be set * @param value value of record to be set * @param tokenId uint256 ID of the token */ function _set(uint256 preset, string memory key, string memory value, uint256 tokenId) internal { uint256 keyHash = uint256(keccak256(bytes(key))); bool isNewKey = bytes(_records[tokenId][preset][key]).length == 0; _registry.sync(tokenId, keyHash); _records[tokenId][preset][key] = value; if (bytes(_hashedKeys[keyHash]).length == 0) { _hashedKeys[keyHash] = key; } if (isNewKey) { emit NewKey(tokenId, key, key); } emit Set(tokenId, key, value, key, value); } /** * @dev Internal function to to set multiple records. As opposed to setMany, this imposes * no restrictions on msg.sender. * @param preset preset to set key/values on * @param keys keys of record to be set * @param values values of record to be set * @param tokenId uint256 ID of the token */ function _setMany(uint256 preset, string[] memory keys, string[] memory values, uint256 tokenId) internal { uint256 keyCount = keys.length; for (uint256 i = 0; i < keyCount; i++) { _set(preset, keys[i], values[i], tokenId); } } /** * @dev Internal function to reset all domain records and set new ones. * @param keys records keys. * @param values records values. * @param tokenId domain token id. */ function _reconfigure(string[] memory keys, string[] memory values, uint256 tokenId) internal { _setPreset(now, tokenId); _setMany(_tokenPresets[tokenId], keys, values, tokenId); } } /** * @title WhitelistedMinter * @dev Defines the functions for distribution of Second Level Domains (SLD)s. */ contract WhitelistedMinter is IMintingController, BulkWhitelistedRole { using ECDSA for bytes32; event Relayed(address indexed sender, address indexed signer, bytes4 indexed funcSig, bytes32 dataHash); string public constant NAME = 'Unstoppable Whitelisted Minter'; string public constant VERSION = '0.3.0'; MintingController internal _mintingController; Resolver internal _resolver; Registry internal _registry; /* * bytes4(keccak256('mintSLD(address,string)')) == 0x4c0b0ed2 */ bytes4 private constant _SIG_MINT = 0x4c0b0ed2; /* * bytes4(keccak256('mintSLDToDefaultResolver(address,string,string[],string[])')) == 0x3d7989fe */ bytes4 private constant _SIG_MINT_DEF_RESOLVER = 0x3d7989fe; /* * bytes4(keccak256('mintSLDToResolver(address,string,string[],string[],address)')) == 0xaceb4764 */ bytes4 private constant _SIG_MINT_RESOLVER = 0xaceb4764; /* * bytes4(keccak256('safeMintSLD(address,string)')) == 0xb2da2979 */ bytes4 private constant _SIG_SAFE_MINT = 0xb2da2979; /* * bytes4(keccak256('safeMintSLD(address,string,bytes)')) == 0xbe362e2e */ bytes4 private constant _SIG_SAFE_MINT_DATA = 0xbe362e2e; /* * bytes4(keccak256('safeMintSLDToDefaultResolver(address,string,string[],string[])')) == 0x61050ffd */ bytes4 private constant _SIG_SAFE_MINT_DEF_RESOLVER = 0x61050ffd; /* * bytes4(keccak256('safeMintSLDToDefaultResolver(address,string,string[],string[],bytes)')) == 0x4b18abea */ bytes4 private constant _SIG_SAFE_MINT_DEF_RESOLVER_DATA = 0x4b18abea; /* * bytes4(keccak256('safeMintSLDToResolver(address,string,string[],string[],address)')) == 0x4b44c01a */ bytes4 private constant _SIG_SAFE_MINT_RESOLVER = 0x4b44c01a; /* * bytes4(keccak256('safeMintSLDToResolver(address,string,string[],string[],bytes,address)')) == 0x898851f8 */ bytes4 private constant _SIG_SAFE_MINT_RESOLVER_DATA = 0x898851f8; constructor(MintingController mintingController) public { _mintingController = mintingController; _registry = Registry(mintingController.registry()); _addWhitelisted(address(this)); } function renounceMinter() external onlyWhitelistAdmin { _mintingController.renounceMinter(); } /** * Renounce whitelisted account with funds' forwarding */ function closeWhitelisted(address payable receiver) external payable onlyWhitelisted { require(receiver != address(0x0), "WhitelistedMinter: RECEIVER_IS_EMPTY"); renounceWhitelisted(); receiver.transfer(msg.value); } /** * Replace whitelisted account by new account with funds' forwarding */ function rotateWhitelisted(address payable receiver) external payable onlyWhitelisted { require(receiver != address(0x0), "WhitelistedMinter: RECEIVER_IS_EMPTY"); _addWhitelisted(receiver); renounceWhitelisted(); receiver.transfer(msg.value); } function mintSLD(address to, string calldata label) external onlyWhitelisted { _mintingController.mintSLD(to, label); } function safeMintSLD(address to, string calldata label) external onlyWhitelisted { _mintingController.safeMintSLD(to, label); } function safeMintSLD( address to, string calldata label, bytes calldata _data ) external onlyWhitelisted { _mintingController.safeMintSLD(to, label, _data); } function mintSLDToDefaultResolver( address to, string memory label, string[] memory keys, string[] memory values ) public onlyWhitelisted { mintSLDToResolver(to, label, keys, values, address(_resolver)); } function mintSLDToResolver( address to, string memory label, string[] memory keys, string[] memory values, address resolver ) public onlyWhitelisted { _mintingController.mintSLDWithResolver(to, label, resolver); preconfigureResolver(label, keys, values, resolver); } function safeMintSLDToDefaultResolver( address to, string memory label, string[] memory keys, string[] memory values ) public onlyWhitelisted { safeMintSLDToResolver(to, label, keys, values, address(_resolver)); } function safeMintSLDToResolver( address to, string memory label, string[] memory keys, string[] memory values, address resolver ) public onlyWhitelisted { _mintingController.safeMintSLDWithResolver(to, label, resolver); preconfigureResolver(label, keys, values, resolver); } function safeMintSLDToDefaultResolver( address to, string memory label, string[] memory keys, string[] memory values, bytes memory _data ) public onlyWhitelisted { safeMintSLDToResolver(to, label, keys, values, _data, address(_resolver)); } function safeMintSLDToResolver( address to, string memory label, string[] memory keys, string[] memory values, bytes memory _data, address resolver ) public onlyWhitelisted { _mintingController.safeMintSLDWithResolver(to, label, resolver, _data); preconfigureResolver(label, keys, values, resolver); } function setDefaultResolver(address resolver) external onlyWhitelistAdmin { _resolver = Resolver(resolver); } function getDefaultResolver() external view returns (address) { return address(_resolver); } /** * Relay allows execute transaction on behalf of whitelisted minter. * The function verify signature of call data parameter before execution. * It allows anybody send transaction on-chain when minter has provided proper parameters. * The function allows to relaying calls of fixed functions. The restriction defined in function `verifyCall` */ function relay(bytes calldata data, bytes calldata signature) external returns(bytes memory) { bytes32 dataHash = keccak256(data); address signer = verifySigner(dataHash, signature); bytes memory _data = data; bytes4 funcSig = verifyCall(_data); /* solium-disable-next-line security/no-low-level-calls */ (bool success, bytes memory result) = address(this).call(data); if (success == false) { /* solium-disable-next-line security/no-inline-assembly */ assembly { let ptr := mload(0x40) let size := returndatasize returndatacopy(ptr, 0, size) revert(ptr, size) } } emit Relayed(msg.sender, signer, funcSig, dataHash); return result; } function preconfigureResolver( string memory label, string[] memory keys, string[] memory values, address resolver ) private { if(keys.length == 0) { return; } Resolver(resolver).preconfigure(keys, values, _registry.childIdOf(_registry.root(), label)); } function verifySigner(bytes32 data, bytes memory signature) private view returns(address signer) { signer = keccak256(abi.encodePacked(data, address(this))) .toEthSignedMessageHash() .recover(signature); require(signer != address(0), 'WhitelistedMinter: SIGNATURE_IS_INVALID'); require(isWhitelisted(signer), 'WhitelistedMinter: SIGNER_IS_NOT_WHITELISTED'); } function verifyCall(bytes memory data) private pure returns(bytes4 sig) { /* solium-disable-next-line security/no-inline-assembly */ assembly { sig := mload(add(data, add(0x20, 0))) } bool isSupported = sig == _SIG_MINT || sig == _SIG_MINT_DEF_RESOLVER || sig == _SIG_MINT_RESOLVER || sig == _SIG_SAFE_MINT || sig == _SIG_SAFE_MINT_DATA || sig == _SIG_SAFE_MINT_DEF_RESOLVER || sig == _SIG_SAFE_MINT_DEF_RESOLVER_DATA || sig == _SIG_SAFE_MINT_RESOLVER || sig == _SIG_SAFE_MINT_RESOLVER_DATA; require(isSupported, 'WhitelistedMinter: UNSUPPORTED_CALL'); } }
File 2 of 3: Registry
// File: @openzeppelin/contracts/introspection/IERC165.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC165 standard, as defined in the * [EIP](https://eips.ethereum.org/EIPS/eip-165). * * 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 * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * 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); } // File: @openzeppelin/contracts/token/ERC721/IERC721.sol pragma solidity ^0.5.0; /** * @dev Required interface of an ERC721 compliant contract. */ contract IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of NFTs in `owner`'s account. */ function balanceOf(address owner) public view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) public view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either `approve` or `setApproveForAll`. */ function safeTransferFrom(address from, address to, uint256 tokenId) public; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either `approve` or `setApproveForAll`. */ function transferFrom(address from, address to, uint256 tokenId) public; function approve(address to, uint256 tokenId) public; function getApproved(uint256 tokenId) public view returns (address operator); function setApprovalForAll(address operator, bool _approved) public; function isApprovedForAll(address owner, address operator) public view returns (bool); function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; } // File: @openzeppelin/contracts/token/ERC721/IERC721Metadata.sol pragma solidity ^0.5.0; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ contract IERC721Metadata is IERC721 { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); } // File: contracts/IRegistry.sol pragma solidity 0.5.12; contract IRegistry is IERC721Metadata { event NewURI(uint256 indexed tokenId, string uri); event NewURIPrefix(string prefix); event Resolve(uint256 indexed tokenId, address indexed to); event Sync(address indexed resolver, uint256 indexed updateId, uint256 indexed tokenId); /** * @dev Controlled function to set the token URI Prefix for all tokens. * @param prefix string URI to assign */ function controlledSetTokenURIPrefix(string calldata prefix) external; /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool); /** * @dev Mints a new a child token. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token not exist. * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the parent token * @param label subdomain label of the child token ID */ function mintChild(address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled function to mint a given token ID. * Requires the msg.sender to be controller. * Requires the token ID to not exist. * @param to address the given token ID will be minted to * @param label string that is a subdomain * @param tokenId uint256 ID of the parent token */ function controlledMintChild(address to, uint256 tokenId, string calldata label) external; /** * @dev Transfers the ownership of a child token ID to another address. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param label subdomain label of the child token ID */ function transferFromChild(address from, address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled function to transfers the ownership of a token ID to * another address. * Requires the msg.sender to be controller. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function controlledTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Safely transfers the ownership of a child token ID to another address. * Calculates child token ID using a namehash function. * Implements a ERC721Reciever check unlike transferFromChild. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 parent ID of the token to be transferred * @param label subdomain label of the child token ID * @param _data bytes data to send along with a safe transfer check */ function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label, bytes calldata _data) external; /// Shorthand for calling the above ^^^ safeTransferFromChild function with an empty _data parameter. Similar to ERC721.safeTransferFrom. function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled frunction to safely transfers the ownership of a token ID * to another address. * Implements a ERC721Reciever check unlike controlledSafeTransferFrom. * Requires the msg.sender to be controller. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 parent ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function controlledSafeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external; /** * @dev Burns a child token ID. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param tokenId uint256 ID of the token to be transferred * @param label subdomain label of the child token ID */ function burnChild(uint256 tokenId, string calldata label) external; /** * @dev Controlled function to burn a given token ID. * Requires the msg.sender to be controller. * Requires the token already exist. * @param tokenId uint256 ID of the token to be burned */ function controlledBurn(uint256 tokenId) external; /** * @dev Sets the resolver of a given token ID to another address. * Requires the msg.sender to be the owner, approved, or operator. * @param to address the given token ID will resolve to * @param tokenId uint256 ID of the token to be transferred */ function resolveTo(address to, uint256 tokenId) external; /** * @dev Gets the resolver of the specified token ID. * @param tokenId uint256 ID of the token to query the resolver of * @return address currently marked as the resolver of the given token ID */ function resolverOf(uint256 tokenId) external view returns (address); /** * @dev Controlled function to sets the resolver of a given token ID. * Requires the msg.sender to be controller. * @param to address the given token ID will resolve to * @param tokenId uint256 ID of the token to be transferred */ function controlledResolveTo(address to, uint256 tokenId) external; } // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol pragma solidity ^0.5.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ contract IERC721Receiver { /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient * after a `safeTransfer`. This function MUST return the function selector, * otherwise the caller will revert the transaction. The selector to be * returned can be obtained as `this.onERC721Received.selector`. This * function MAY throw to revert and reject the transfer. * Note: the ERC721 contract address is always the message sender. * @param operator The address which called `safeTransferFrom` function * @param from The address which previously owned the token * @param tokenId The NFT identifier which is being transferred * @param data Additional data with no specified format * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4); } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.5.0; /** * @dev Collection of functions related to the address type, */ library Address { /** * @dev Returns true if `account` is a contract. * * This test is non-exhaustive, and there may be false-negatives: during the * execution of a contract's constructor, its address will be reported as * not containing a contract. * * > It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: @openzeppelin/contracts/drafts/Counters.sol pragma solidity ^0.5.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // File: @openzeppelin/contracts/introspection/ERC165.sol pragma solidity ^0.5.0; /** * @dev Implementation of the `IERC165` interface. * * Contracts may inherit from this and call `_registerInterface` to declare * their support of an interface. */ contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See `IERC165.supportsInterface`. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See `IERC165.supportsInterface`. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } // File: @openzeppelin/contracts/token/ERC721/ERC721.sol pragma solidity ^0.5.0; /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is ERC165, IERC721 { using SafeMath for uint256; using Address for address; using Counters for Counters.Counter; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // Mapping from token ID to owner mapping (uint256 => address) private _tokenOwner; // Mapping from token ID to approved address mapping (uint256 => address) private _tokenApprovals; // Mapping from owner to number of owned token mapping (address => Counters.Counter) private _ownedTokensCount; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; /* * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ * 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd */ bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; constructor () public { // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_ERC721); } /** * @dev Gets the balance of the specified address. * @param owner address to query the balance of * @return uint256 representing the amount owned by the passed address */ function balanceOf(address owner) public view returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _ownedTokensCount[owner].current(); } /** * @dev Gets the owner of the specified token ID. * @param tokenId uint256 ID of the token to query the owner of * @return address currently marked as the owner of the given token ID */ function ownerOf(uint256 tokenId) public view returns (address) { address owner = _tokenOwner[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev Approves another address to transfer the given token ID * The zero address indicates there is no approved address. * There can only be one approved address per token at a given time. * Can only be called by the token owner or an approved operator. * @param to address to be approved for the given token ID * @param tokenId uint256 ID of the token to be approved */ function approve(address to, uint256 tokenId) public { address owner = ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "ERC721: approve caller is not owner nor approved for all" ); _tokenApprovals[tokenId] = to; emit Approval(owner, to, tokenId); } /** * @dev Gets the approved address for a token ID, or zero if no address set * Reverts if the token ID does not exist. * @param tokenId uint256 ID of the token to query the approval of * @return address currently approved for the given token ID */ function getApproved(uint256 tokenId) public view returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev Sets or unsets the approval of a given operator * An operator is allowed to transfer all tokens of the sender on their behalf. * @param to operator address to set the approval * @param approved representing the status of the approval to be set */ function setApprovalForAll(address to, bool approved) public { require(to != msg.sender, "ERC721: approve to caller"); _operatorApprovals[msg.sender][to] = approved; emit ApprovalForAll(msg.sender, to, approved); } /** * @dev Tells whether an operator is approved by a given owner. * @param owner owner address which you want to query the approval of * @param operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ function isApprovedForAll(address owner, address operator) public view returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev Transfers the ownership of a given token ID to another address. * Usage of this method is discouraged, use `safeTransferFrom` whenever possible. * Requires the msg.sender to be the owner, approved, or operator. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function transferFrom(address from, address to, uint256 tokenId) public { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved"); _transferFrom(from, to, tokenId); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function safeTransferFrom(address from, address to, uint256 tokenId) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether the specified token exists. * @param tokenId uint256 ID of the token to query the existence of * @return bool whether the token exists */ function _exists(uint256 tokenId) internal view returns (bool) { address owner = _tokenOwner[tokenId]; return owner != address(0); } /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Internal function to mint a new token. * Reverts if the given token ID already exists. * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted */ function _mint(address to, uint256 tokenId) internal { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _tokenOwner[tokenId] = to; _ownedTokensCount[to].increment(); emit Transfer(address(0), to, tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * Deprecated, use _burn(uint256) instead. * @param owner owner of the token to burn * @param tokenId uint256 ID of the token being burned */ function _burn(address owner, uint256 tokenId) internal { require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own"); _clearApproval(tokenId); _ownedTokensCount[owner].decrement(); _tokenOwner[tokenId] = address(0); emit Transfer(owner, address(0), tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * @param tokenId uint256 ID of the token being burned */ function _burn(uint256 tokenId) internal { _burn(ownerOf(tokenId), tokenId); } /** * @dev Internal function to transfer ownership of a given token ID to another address. * As opposed to transferFrom, this imposes no restrictions on msg.sender. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function _transferFrom(address from, address to, uint256 tokenId) internal { require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _clearApproval(tokenId); _ownedTokensCount[from].decrement(); _ownedTokensCount[to].increment(); _tokenOwner[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @dev Internal function to invoke `onERC721Received` on a target address. * The call is not executed if the target address is not a contract. * * This function is deprecated. * @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) internal returns (bool) { if (!to.isContract()) { return true; } bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data); return (retval == _ERC721_RECEIVED); } /** * @dev Private function to clear current approval of a given token ID. * @param tokenId uint256 ID of the token to be transferred */ function _clearApproval(uint256 tokenId) private { if (_tokenApprovals[tokenId] != address(0)) { _tokenApprovals[tokenId] = address(0); } } } // File: @openzeppelin/contracts/token/ERC721/ERC721Burnable.sol pragma solidity ^0.5.0; /** * @title ERC721 Burnable Token * @dev ERC721 Token that can be irreversibly burned (destroyed). */ contract ERC721Burnable is ERC721 { /** * @dev Burns a specific ERC721 token. * @param tokenId uint256 id of the ERC721 token to be burned. */ function burn(uint256 tokenId) public { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); } } // File: @openzeppelin/contracts/access/Roles.sol pragma solidity ^0.5.0; /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev Give an account access to this role. */ function add(Role storage role, address account) internal { require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } /** * @dev Remove an account's access to this role. */ function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } /** * @dev Check if an account has this role. * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } } // File: contracts/util/ControllerRole.sol pragma solidity 0.5.12; // solium-disable error-reason /** * @title ControllerRole * @dev An Controller role defined using the Open Zeppelin Role system. */ contract ControllerRole { using Roles for Roles.Role; // NOTE: Commented out standard Role events to save gas. // event ControllerAdded(address indexed account); // event ControllerRemoved(address indexed account); Roles.Role private _controllers; constructor () public { _addController(msg.sender); } modifier onlyController() { require(isController(msg.sender)); _; } function isController(address account) public view returns (bool) { return _controllers.has(account); } function addController(address account) public onlyController { _addController(account); } function renounceController() public { _removeController(msg.sender); } function _addController(address account) internal { _controllers.add(account); // emit ControllerAdded(account); } function _removeController(address account) internal { _controllers.remove(account); // emit ControllerRemoved(account); } } // File: contracts/Registry.sol pragma solidity 0.5.12; // solium-disable no-empty-blocks,error-reason /** * @title Registry * @dev An ERC721 Token see https://eips.ethereum.org/EIPS/eip-721. With * additional functions so other trusted contracts to interact with the tokens. */ contract Registry is IRegistry, ControllerRole, ERC721Burnable { // Optional mapping for token URIs mapping(uint256 => string) internal _tokenURIs; string internal _prefix; // Mapping from token ID to resolver address mapping (uint256 => address) internal _tokenResolvers; // uint256(keccak256(abi.encodePacked(uint256(0x0), keccak256(abi.encodePacked("crypto"))))) uint256 private constant _CRYPTO_HASH = 0x0f4a10a4f46c288cea365fcf45cccf0e9d901b945b9829ccdb54c10dc3cb7a6f; modifier onlyApprovedOrOwner(uint256 tokenId) { require(_isApprovedOrOwner(msg.sender, tokenId)); _; } constructor () public { _mint(address(0xdead), _CRYPTO_HASH); // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(0x5b5e139f); // ERC721 Metadata Interface _tokenURIs[root()] = "crypto"; emit NewURI(root(), "crypto"); } /// ERC721 Metadata extension function name() external view returns (string memory) { return ".crypto"; } function symbol() external view returns (string memory) { return "UD"; } function tokenURI(uint256 tokenId) external view returns (string memory) { require(_exists(tokenId)); return string(abi.encodePacked(_prefix, _tokenURIs[tokenId])); } function controlledSetTokenURIPrefix(string calldata prefix) external onlyController { _prefix = prefix; emit NewURIPrefix(prefix); } /// Ownership function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool) { return _isApprovedOrOwner(spender, tokenId); } /// Registry Constants function root() public pure returns (uint256) { return _CRYPTO_HASH; } function childIdOf(uint256 tokenId, string calldata label) external pure returns (uint256) { return _childId(tokenId, label); } /// Minting function mintChild(address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _mintChild(to, tokenId, label); } function controlledMintChild(address to, uint256 tokenId, string calldata label) external onlyController { _mintChild(to, tokenId, label); } function safeMintChild(address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _safeMintChild(to, tokenId, label, ""); } function safeMintChild(address to, uint256 tokenId, string calldata label, bytes calldata _data) external onlyApprovedOrOwner(tokenId) { _safeMintChild(to, tokenId, label, _data); } function controlledSafeMintChild(address to, uint256 tokenId, string calldata label, bytes calldata _data) external onlyController { _safeMintChild(to, tokenId, label, _data); } /// Transfering function setOwner(address to, uint256 tokenId) external onlyApprovedOrOwner(tokenId) { super._transferFrom(ownerOf(tokenId), to, tokenId); } function transferFromChild(address from, address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _transferFrom(from, to, _childId(tokenId, label)); } function controlledTransferFrom(address from, address to, uint256 tokenId) external onlyController { _transferFrom(from, to, tokenId); } function safeTransferFromChild( address from, address to, uint256 tokenId, string memory label, bytes memory _data ) public onlyApprovedOrOwner(tokenId) { uint256 childId = _childId(tokenId, label); _transferFrom(from, to, childId); require(_checkOnERC721Received(from, to, childId, _data)); } function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label) external { safeTransferFromChild(from, to, tokenId, label, ""); } function controlledSafeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external onlyController { _transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data)); } /// Burning function burnChild(uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _burn(_childId(tokenId, label)); } function controlledBurn(uint256 tokenId) external onlyController { _burn(tokenId); } /// Resolution function resolverOf(uint256 tokenId) external view returns (address) { address resolver = _tokenResolvers[tokenId]; require(resolver != address(0)); return resolver; } function resolveTo(address to, uint256 tokenId) external onlyApprovedOrOwner(tokenId) { _resolveTo(to, tokenId); } function controlledResolveTo(address to, uint256 tokenId) external onlyController { _resolveTo(to, tokenId); } function sync(uint256 tokenId, uint256 updateId) external { require(_tokenResolvers[tokenId] == msg.sender); emit Sync(msg.sender, updateId, tokenId); } /// Internal function _childId(uint256 tokenId, string memory label) internal pure returns (uint256) { require(bytes(label).length != 0); return uint256(keccak256(abi.encodePacked(tokenId, keccak256(abi.encodePacked(label))))); } function _mintChild(address to, uint256 tokenId, string memory label) internal { uint256 childId = _childId(tokenId, label); _mint(to, childId); require(bytes(label).length != 0); require(_exists(childId)); bytes memory domain = abi.encodePacked(label, ".", _tokenURIs[tokenId]); _tokenURIs[childId] = string(domain); emit NewURI(childId, string(domain)); } function _safeMintChild(address to, uint256 tokenId, string memory label, bytes memory _data) internal { _mintChild(to, tokenId, label); require(_checkOnERC721Received(address(0), to, _childId(tokenId, label), _data)); } function _transferFrom(address from, address to, uint256 tokenId) internal { super._transferFrom(from, to, tokenId); // Clear resolver (if any) if (_tokenResolvers[tokenId] != address(0x0)) { delete _tokenResolvers[tokenId]; } } function _burn(uint256 tokenId) internal { super._burn(tokenId); // Clear resolver (if any) if (_tokenResolvers[tokenId] != address(0x0)) { delete _tokenResolvers[tokenId]; } // Clear metadata (if any) if (bytes(_tokenURIs[tokenId]).length != 0) { delete _tokenURIs[tokenId]; } } function _resolveTo(address to, uint256 tokenId) internal { require(_exists(tokenId)); emit Resolve(tokenId, to); _tokenResolvers[tokenId] = to; } }
File 3 of 3: MintingController
// File: @openzeppelin/contracts/access/Roles.sol pragma solidity ^0.5.0; /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev Give an account access to this role. */ function add(Role storage role, address account) internal { require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } /** * @dev Remove an account's access to this role. */ function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } /** * @dev Check if an account has this role. * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } } // File: @openzeppelin/contracts/access/roles/MinterRole.sol pragma solidity ^0.5.0; contract MinterRole { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; constructor () internal { _addMinter(msg.sender); } modifier onlyMinter() { require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role"); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(msg.sender); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } } // File: contracts/controllers/IMintingController.sol pragma solidity 0.5.12; interface IMintingController { /** * @dev Minter function that mints a Second Level Domain (SLD). * @param to address to mint the new SLD to. * @param label SLD label to mint. */ function mintSLD(address to, string calldata label) external; /** * @dev Minter function that safely mints a Second Level Domain (SLD). * Implements a ERC721Reciever check unlike mintSLD. * @param to address to mint the new SLD to. * @param label SLD label to mint. */ function safeMintSLD(address to, string calldata label) external; /** * @dev Minter function that safely mints a Second Level Domain (SLD). * Implements a ERC721Reciever check unlike mintSLD. * @param to address to mint the new SLD to. * @param label SLD label to mint. * @param _data bytes data to send along with a safe transfer check */ function safeMintSLD(address to, string calldata label, bytes calldata _data) external; } // File: @openzeppelin/contracts/introspection/IERC165.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC165 standard, as defined in the * [EIP](https://eips.ethereum.org/EIPS/eip-165). * * 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 * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * 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); } // File: @openzeppelin/contracts/token/ERC721/IERC721.sol pragma solidity ^0.5.0; /** * @dev Required interface of an ERC721 compliant contract. */ contract IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of NFTs in `owner`'s account. */ function balanceOf(address owner) public view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) public view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either `approve` or `setApproveForAll`. */ function safeTransferFrom(address from, address to, uint256 tokenId) public; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either `approve` or `setApproveForAll`. */ function transferFrom(address from, address to, uint256 tokenId) public; function approve(address to, uint256 tokenId) public; function getApproved(uint256 tokenId) public view returns (address operator); function setApprovalForAll(address operator, bool _approved) public; function isApprovedForAll(address owner, address operator) public view returns (bool); function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; } // File: @openzeppelin/contracts/token/ERC721/IERC721Metadata.sol pragma solidity ^0.5.0; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ contract IERC721Metadata is IERC721 { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); } // File: contracts/IRegistry.sol pragma solidity 0.5.12; contract IRegistry is IERC721Metadata { event NewURI(uint256 indexed tokenId, string uri); event NewURIPrefix(string prefix); event Resolve(uint256 indexed tokenId, address indexed to); event Sync(address indexed resolver, uint256 indexed updateId, uint256 indexed tokenId); /** * @dev Controlled function to set the token URI Prefix for all tokens. * @param prefix string URI to assign */ function controlledSetTokenURIPrefix(string calldata prefix) external; /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool); /** * @dev Mints a new a child token. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token not exist. * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the parent token * @param label subdomain label of the child token ID */ function mintChild(address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled function to mint a given token ID. * Requires the msg.sender to be controller. * Requires the token ID to not exist. * @param to address the given token ID will be minted to * @param label string that is a subdomain * @param tokenId uint256 ID of the parent token */ function controlledMintChild(address to, uint256 tokenId, string calldata label) external; /** * @dev Transfers the ownership of a child token ID to another address. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param label subdomain label of the child token ID */ function transferFromChild(address from, address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled function to transfers the ownership of a token ID to * another address. * Requires the msg.sender to be controller. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function controlledTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Safely transfers the ownership of a child token ID to another address. * Calculates child token ID using a namehash function. * Implements a ERC721Reciever check unlike transferFromChild. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 parent ID of the token to be transferred * @param label subdomain label of the child token ID * @param _data bytes data to send along with a safe transfer check */ function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label, bytes calldata _data) external; /// Shorthand for calling the above ^^^ safeTransferFromChild function with an empty _data parameter. Similar to ERC721.safeTransferFrom. function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label) external; /** * @dev Controlled frunction to safely transfers the ownership of a token ID * to another address. * Implements a ERC721Reciever check unlike controlledSafeTransferFrom. * Requires the msg.sender to be controller. * Requires the token already exist. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 parent ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function controlledSafeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external; /** * @dev Burns a child token ID. * Calculates child token ID using a namehash function. * Requires the msg.sender to be the owner, approved, or operator of tokenId. * Requires the token already exist. * @param tokenId uint256 ID of the token to be transferred * @param label subdomain label of the child token ID */ function burnChild(uint256 tokenId, string calldata label) external; /** * @dev Controlled function to burn a given token ID. * Requires the msg.sender to be controller. * Requires the token already exist. * @param tokenId uint256 ID of the token to be burned */ function controlledBurn(uint256 tokenId) external; /** * @dev Sets the resolver of a given token ID to another address. * Requires the msg.sender to be the owner, approved, or operator. * @param to address the given token ID will resolve to * @param tokenId uint256 ID of the token to be transferred */ function resolveTo(address to, uint256 tokenId) external; /** * @dev Gets the resolver of the specified token ID. * @param tokenId uint256 ID of the token to query the resolver of * @return address currently marked as the resolver of the given token ID */ function resolverOf(uint256 tokenId) external view returns (address); /** * @dev Controlled function to sets the resolver of a given token ID. * Requires the msg.sender to be controller. * @param to address the given token ID will resolve to * @param tokenId uint256 ID of the token to be transferred */ function controlledResolveTo(address to, uint256 tokenId) external; } // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol pragma solidity ^0.5.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ contract IERC721Receiver { /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient * after a `safeTransfer`. This function MUST return the function selector, * otherwise the caller will revert the transaction. The selector to be * returned can be obtained as `this.onERC721Received.selector`. This * function MAY throw to revert and reject the transfer. * Note: the ERC721 contract address is always the message sender. * @param operator The address which called `safeTransferFrom` function * @param from The address which previously owned the token * @param tokenId The NFT identifier which is being transferred * @param data Additional data with no specified format * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4); } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.5.0; /** * @dev Collection of functions related to the address type, */ library Address { /** * @dev Returns true if `account` is a contract. * * This test is non-exhaustive, and there may be false-negatives: during the * execution of a contract's constructor, its address will be reported as * not containing a contract. * * > It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: @openzeppelin/contracts/drafts/Counters.sol pragma solidity ^0.5.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // File: @openzeppelin/contracts/introspection/ERC165.sol pragma solidity ^0.5.0; /** * @dev Implementation of the `IERC165` interface. * * Contracts may inherit from this and call `_registerInterface` to declare * their support of an interface. */ contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See `IERC165.supportsInterface`. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See `IERC165.supportsInterface`. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } // File: @openzeppelin/contracts/token/ERC721/ERC721.sol pragma solidity ^0.5.0; /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is ERC165, IERC721 { using SafeMath for uint256; using Address for address; using Counters for Counters.Counter; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // Mapping from token ID to owner mapping (uint256 => address) private _tokenOwner; // Mapping from token ID to approved address mapping (uint256 => address) private _tokenApprovals; // Mapping from owner to number of owned token mapping (address => Counters.Counter) private _ownedTokensCount; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; /* * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ * 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd */ bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; constructor () public { // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_ERC721); } /** * @dev Gets the balance of the specified address. * @param owner address to query the balance of * @return uint256 representing the amount owned by the passed address */ function balanceOf(address owner) public view returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _ownedTokensCount[owner].current(); } /** * @dev Gets the owner of the specified token ID. * @param tokenId uint256 ID of the token to query the owner of * @return address currently marked as the owner of the given token ID */ function ownerOf(uint256 tokenId) public view returns (address) { address owner = _tokenOwner[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev Approves another address to transfer the given token ID * The zero address indicates there is no approved address. * There can only be one approved address per token at a given time. * Can only be called by the token owner or an approved operator. * @param to address to be approved for the given token ID * @param tokenId uint256 ID of the token to be approved */ function approve(address to, uint256 tokenId) public { address owner = ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "ERC721: approve caller is not owner nor approved for all" ); _tokenApprovals[tokenId] = to; emit Approval(owner, to, tokenId); } /** * @dev Gets the approved address for a token ID, or zero if no address set * Reverts if the token ID does not exist. * @param tokenId uint256 ID of the token to query the approval of * @return address currently approved for the given token ID */ function getApproved(uint256 tokenId) public view returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev Sets or unsets the approval of a given operator * An operator is allowed to transfer all tokens of the sender on their behalf. * @param to operator address to set the approval * @param approved representing the status of the approval to be set */ function setApprovalForAll(address to, bool approved) public { require(to != msg.sender, "ERC721: approve to caller"); _operatorApprovals[msg.sender][to] = approved; emit ApprovalForAll(msg.sender, to, approved); } /** * @dev Tells whether an operator is approved by a given owner. * @param owner owner address which you want to query the approval of * @param operator operator address which you want to query the approval of * @return bool whether the given operator is approved by the given owner */ function isApprovedForAll(address owner, address operator) public view returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev Transfers the ownership of a given token ID to another address. * Usage of this method is discouraged, use `safeTransferFrom` whenever possible. * Requires the msg.sender to be the owner, approved, or operator. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function transferFrom(address from, address to, uint256 tokenId) public { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved"); _transferFrom(from, to, tokenId); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function safeTransferFrom(address from, address to, uint256 tokenId) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev Safely transfers the ownership of a given token ID to another address * If the target address is a contract, it must implement `onERC721Received`, * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. * Requires the msg.sender to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred * @param _data bytes data to send along with a safe transfer check */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether the specified token exists. * @param tokenId uint256 ID of the token to query the existence of * @return bool whether the token exists */ function _exists(uint256 tokenId) internal view returns (bool) { address owner = _tokenOwner[tokenId]; return owner != address(0); } /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Internal function to mint a new token. * Reverts if the given token ID already exists. * @param to The address that will own the minted token * @param tokenId uint256 ID of the token to be minted */ function _mint(address to, uint256 tokenId) internal { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _tokenOwner[tokenId] = to; _ownedTokensCount[to].increment(); emit Transfer(address(0), to, tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * Deprecated, use _burn(uint256) instead. * @param owner owner of the token to burn * @param tokenId uint256 ID of the token being burned */ function _burn(address owner, uint256 tokenId) internal { require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own"); _clearApproval(tokenId); _ownedTokensCount[owner].decrement(); _tokenOwner[tokenId] = address(0); emit Transfer(owner, address(0), tokenId); } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * @param tokenId uint256 ID of the token being burned */ function _burn(uint256 tokenId) internal { _burn(ownerOf(tokenId), tokenId); } /** * @dev Internal function to transfer ownership of a given token ID to another address. * As opposed to transferFrom, this imposes no restrictions on msg.sender. * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred */ function _transferFrom(address from, address to, uint256 tokenId) internal { require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _clearApproval(tokenId); _ownedTokensCount[from].decrement(); _ownedTokensCount[to].increment(); _tokenOwner[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @dev Internal function to invoke `onERC721Received` on a target address. * The call is not executed if the target address is not a contract. * * This function is deprecated. * @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) internal returns (bool) { if (!to.isContract()) { return true; } bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data); return (retval == _ERC721_RECEIVED); } /** * @dev Private function to clear current approval of a given token ID. * @param tokenId uint256 ID of the token to be transferred */ function _clearApproval(uint256 tokenId) private { if (_tokenApprovals[tokenId] != address(0)) { _tokenApprovals[tokenId] = address(0); } } } // File: @openzeppelin/contracts/token/ERC721/ERC721Burnable.sol pragma solidity ^0.5.0; /** * @title ERC721 Burnable Token * @dev ERC721 Token that can be irreversibly burned (destroyed). */ contract ERC721Burnable is ERC721 { /** * @dev Burns a specific ERC721 token. * @param tokenId uint256 id of the ERC721 token to be burned. */ function burn(uint256 tokenId) public { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); } } // File: contracts/util/ControllerRole.sol pragma solidity 0.5.12; // solium-disable error-reason /** * @title ControllerRole * @dev An Controller role defined using the Open Zeppelin Role system. */ contract ControllerRole { using Roles for Roles.Role; // NOTE: Commented out standard Role events to save gas. // event ControllerAdded(address indexed account); // event ControllerRemoved(address indexed account); Roles.Role private _controllers; constructor () public { _addController(msg.sender); } modifier onlyController() { require(isController(msg.sender)); _; } function isController(address account) public view returns (bool) { return _controllers.has(account); } function addController(address account) public onlyController { _addController(account); } function renounceController() public { _removeController(msg.sender); } function _addController(address account) internal { _controllers.add(account); // emit ControllerAdded(account); } function _removeController(address account) internal { _controllers.remove(account); // emit ControllerRemoved(account); } } // File: contracts/Registry.sol pragma solidity 0.5.12; // solium-disable no-empty-blocks,error-reason /** * @title Registry * @dev An ERC721 Token see https://eips.ethereum.org/EIPS/eip-721. With * additional functions so other trusted contracts to interact with the tokens. */ contract Registry is IRegistry, ControllerRole, ERC721Burnable { // Optional mapping for token URIs mapping(uint256 => string) internal _tokenURIs; string internal _prefix; // Mapping from token ID to resolver address mapping (uint256 => address) internal _tokenResolvers; // uint256(keccak256(abi.encodePacked(uint256(0x0), keccak256(abi.encodePacked("crypto"))))) uint256 private constant _CRYPTO_HASH = 0x0f4a10a4f46c288cea365fcf45cccf0e9d901b945b9829ccdb54c10dc3cb7a6f; modifier onlyApprovedOrOwner(uint256 tokenId) { require(_isApprovedOrOwner(msg.sender, tokenId)); _; } constructor () public { _mint(address(0xdead), _CRYPTO_HASH); // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(0x5b5e139f); // ERC721 Metadata Interface _tokenURIs[root()] = "crypto"; emit NewURI(root(), "crypto"); } /// ERC721 Metadata extension function name() external view returns (string memory) { return ".crypto"; } function symbol() external view returns (string memory) { return "UD"; } function tokenURI(uint256 tokenId) external view returns (string memory) { require(_exists(tokenId)); return string(abi.encodePacked(_prefix, _tokenURIs[tokenId])); } function controlledSetTokenURIPrefix(string calldata prefix) external onlyController { _prefix = prefix; emit NewURIPrefix(prefix); } /// Ownership function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool) { return _isApprovedOrOwner(spender, tokenId); } /// Registry Constants function root() public pure returns (uint256) { return _CRYPTO_HASH; } function childIdOf(uint256 tokenId, string calldata label) external pure returns (uint256) { return _childId(tokenId, label); } /// Minting function mintChild(address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _mintChild(to, tokenId, label); } function controlledMintChild(address to, uint256 tokenId, string calldata label) external onlyController { _mintChild(to, tokenId, label); } function safeMintChild(address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _safeMintChild(to, tokenId, label, ""); } function safeMintChild(address to, uint256 tokenId, string calldata label, bytes calldata _data) external onlyApprovedOrOwner(tokenId) { _safeMintChild(to, tokenId, label, _data); } function controlledSafeMintChild(address to, uint256 tokenId, string calldata label, bytes calldata _data) external onlyController { _safeMintChild(to, tokenId, label, _data); } /// Transfering function setOwner(address to, uint256 tokenId) external onlyApprovedOrOwner(tokenId) { super._transferFrom(ownerOf(tokenId), to, tokenId); } function transferFromChild(address from, address to, uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _transferFrom(from, to, _childId(tokenId, label)); } function controlledTransferFrom(address from, address to, uint256 tokenId) external onlyController { _transferFrom(from, to, tokenId); } function safeTransferFromChild( address from, address to, uint256 tokenId, string memory label, bytes memory _data ) public onlyApprovedOrOwner(tokenId) { uint256 childId = _childId(tokenId, label); _transferFrom(from, to, childId); require(_checkOnERC721Received(from, to, childId, _data)); } function safeTransferFromChild(address from, address to, uint256 tokenId, string calldata label) external { safeTransferFromChild(from, to, tokenId, label, ""); } function controlledSafeTransferFrom(address from, address to, uint256 tokenId, bytes calldata _data) external onlyController { _transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data)); } /// Burning function burnChild(uint256 tokenId, string calldata label) external onlyApprovedOrOwner(tokenId) { _burn(_childId(tokenId, label)); } function controlledBurn(uint256 tokenId) external onlyController { _burn(tokenId); } /// Resolution function resolverOf(uint256 tokenId) external view returns (address) { address resolver = _tokenResolvers[tokenId]; require(resolver != address(0)); return resolver; } function resolveTo(address to, uint256 tokenId) external onlyApprovedOrOwner(tokenId) { _resolveTo(to, tokenId); } function controlledResolveTo(address to, uint256 tokenId) external onlyController { _resolveTo(to, tokenId); } function sync(uint256 tokenId, uint256 updateId) external { require(_tokenResolvers[tokenId] == msg.sender); emit Sync(msg.sender, updateId, tokenId); } /// Internal function _childId(uint256 tokenId, string memory label) internal pure returns (uint256) { require(bytes(label).length != 0); return uint256(keccak256(abi.encodePacked(tokenId, keccak256(abi.encodePacked(label))))); } function _mintChild(address to, uint256 tokenId, string memory label) internal { uint256 childId = _childId(tokenId, label); _mint(to, childId); require(bytes(label).length != 0); require(_exists(childId)); bytes memory domain = abi.encodePacked(label, ".", _tokenURIs[tokenId]); _tokenURIs[childId] = string(domain); emit NewURI(childId, string(domain)); } function _safeMintChild(address to, uint256 tokenId, string memory label, bytes memory _data) internal { _mintChild(to, tokenId, label); require(_checkOnERC721Received(address(0), to, _childId(tokenId, label), _data)); } function _transferFrom(address from, address to, uint256 tokenId) internal { super._transferFrom(from, to, tokenId); // Clear resolver (if any) if (_tokenResolvers[tokenId] != address(0x0)) { delete _tokenResolvers[tokenId]; } } function _burn(uint256 tokenId) internal { super._burn(tokenId); // Clear resolver (if any) if (_tokenResolvers[tokenId] != address(0x0)) { delete _tokenResolvers[tokenId]; } // Clear metadata (if any) if (bytes(_tokenURIs[tokenId]).length != 0) { delete _tokenURIs[tokenId]; } } function _resolveTo(address to, uint256 tokenId) internal { require(_exists(tokenId)); emit Resolve(tokenId, to); _tokenResolvers[tokenId] = to; } } // File: contracts/controllers/MintingController.sol pragma solidity 0.5.12; /** * @title MintingController * @dev Defines the functions for distribution of Second Level Domains (SLD)s. */ contract MintingController is IMintingController, MinterRole { Registry internal _registry; constructor (Registry registry) public { _registry = registry; } function registry() external view returns (address) { return address(_registry); } function mintSLD(address to, string memory label) public onlyMinter { _registry.controlledMintChild(to, _registry.root(), label); } function safeMintSLD(address to, string calldata label) external { safeMintSLD(to, label, ""); } function safeMintSLD(address to, string memory label, bytes memory _data) public onlyMinter { _registry.controlledSafeMintChild(to, _registry.root(), label, _data); } function mintSLDWithResolver(address to, string memory label, address resolver) public onlyMinter { _registry.controlledMintChild(to, _registry.root(), label); _registry.controlledResolveTo(resolver, _registry.childIdOf(_registry.root(), label)); } function safeMintSLDWithResolver(address to, string calldata label, address resolver) external { safeMintSLD(to, label, ""); _registry.controlledResolveTo(resolver, _registry.childIdOf(_registry.root(), label)); } function safeMintSLDWithResolver(address to, string calldata label, address resolver, bytes calldata _data) external { safeMintSLD(to, label, _data); _registry.controlledResolveTo(resolver, _registry.childIdOf(_registry.root(), label)); } }