forked from unstoppabledomains/dot-crypto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCNSRegistry.sol
228 lines (177 loc) · 7.19 KB
/
CNSRegistry.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
pragma solidity 0.5.12;
import "./ICNSRegistry.sol";
import "@openzeppelin/contracts-2.3/token/ERC721/ERC721Burnable.sol";
import "./util/ControllerRole.sol";
// solium-disable no-empty-blocks,error-reason
/**
* @title CNS 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 CNSRegistry is ICNSRegistry, 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;
}
}