CraftNFT.sol (19725B)
1 pragma solidity >= 0.8.0; 2 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 5 contract CraftNFT { 6 // Defines the behavior of a single token batch. 7 // 8 // count defines the amount of tokens there are in a batch. A count of 0 indicates a unique token. 9 // A batched token can never have a token count of 0 in any batch. 10 // 11 // cursor keeps track of how many tokens have been minted in the batch. 12 // 13 // If sparse is set, token indexes in mintedToken may not be in order. 14 // In this case a full iteration up to count is required to discover all minted tokens. 15 struct tokenSpec { 16 uint48 count; 17 uint48 cursor; 18 bool sparse; 19 bool capped; 20 } 21 22 // 0xc22876c3 - ERC721 23 // 0xd283ef1d - ERC721 (Metadata) 24 // 0xdd9d2087 - ERC721 (Enumerable) 25 // 0x449a52f8 - Minter 26 // 0xabe1f1f5 - Writer 27 // 0xed75b333 - Locator 28 // 0xf0440c0f - Msg 29 // 0x982ab05d - Digest 30 uint256 constant interfaces = 0xc22876c3d283ef1ddd9d2087449a52f8abe1f1f5ed75b333f0440c0f982ab05d; 31 32 // The owner of the token contract. 33 // Only the owner may mint tokens. 34 // Implements ERC173 35 address public owner; 36 37 // Addresses with access to allocate and mint tokens.. 38 mapping ( address => bool ) writer; 39 40 // If set, ownership of the token contract cannot change. 41 bool ownerFinal; 42 43 // Collection of all unique token keys 44 bytes32[] public tokens; 45 46 // Define each batch of a token. (A unqiue token will have a single entry only). 47 mapping(bytes32 => tokenSpec[]) public token; 48 49 // All Minted Tokens. 50 // Represents both Unique Tokens and Batch Tokens. 51 mapping(bytes32 => bytes32) public mintedToken; 52 53 // List of tokens in order of minting 54 // Implements ERC721Enumerable 55 uint256[] public tokenByIndex; 56 57 // Registry for the approve() method 58 mapping(uint256 => address) tokenAllowance; 59 60 // Registry for the setApprovalForAll() method 61 mapping(address => address) tokenOperator; 62 63 // Implements ERC721Metadata 64 string public name; 65 66 // Implements ERC721Metadata 67 string public symbol; 68 69 // Editable base URI against which to look up token data by token id 70 bytes public baseURL; 71 72 // Enumerated index of all owned tokens 73 // Implements ERC721Enumerable 74 mapping ( address => mapping ( uint256 => uint256 ) ) public tokenOfOwnerByIndex; 75 mapping ( uint256 => uint256 ) ownerIndexReverse; 76 mapping ( address => uint256 ) balance; 77 78 // Implements ERC721 79 event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); 80 // Implements ERC721 81 event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); 82 // Implements ERC721 83 event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); 84 event TransferWithData(address indexed _from, address indexed _to, uint256 indexed _tokenId, bytes32 _data); 85 86 // Implements Minter 87 event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value); 88 89 event Allocate(address indexed _minter, uint48 indexed _count, bool indexed _capped, bytes32 _tokenId); 90 91 // Implements ERC173 92 event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 93 94 // Content hashes 95 // Represents a multicodec item 96 struct MultiHash { 97 uint8 l; 98 uint8 codecRLength; 99 uint8 prefixRLength; 100 bytes16 prefix; 101 bytes8 codec; 102 } 103 // All registered multicodecs 104 mapping (uint256 => MultiHash) public multiHash; 105 bytes currentMsg; 106 // Implements Digest 107 uint256 public defaultDigestEncoding; 108 109 // Implements Msg 110 event Msg(bytes _multiHash); 111 112 constructor(string memory _name, string memory _symbol) { 113 owner = msg.sender; 114 name = _name; 115 symbol = _symbol; 116 addMultiCodec(32, 0x12, "sha256"); 117 defaultDigestEncoding = 0x12; 118 currentMsg = new bytes(32); 119 } 120 121 // Transfer ownership of token contract to new owner. 122 // 123 // If _final is true, future ownership transfers will not be permitted. 124 function transferOwnership(address _newOwner) public returns(bool) { 125 address oldOwner; 126 127 require(msg.sender == owner); 128 oldOwner = owner; 129 owner = _newOwner; 130 emit OwnershipTransferred(oldOwner, owner); 131 return true; 132 } 133 134 // implements Writer 135 function addWriter(address _writer) public { 136 require(msg.sender == owner, 'ERR_ACCESS'); 137 writer[_writer] = true; 138 } 139 140 // implements Writer 141 function deleteWriter(address _writer) public { 142 require(msg.sender == _writer || msg.sender == owner, 'ERR_ACCESS'); 143 writer[_writer] = false; 144 } 145 146 // implements Writer 147 function isWriter(address _writer) public view returns(bool) { 148 return writer[_writer] || _writer == owner; 149 } 150 151 // Check bit that is always set on the content data when a token has been minted. 152 function isActive(bytes32 _tokenContent) private pure returns(bool) { 153 return uint256(_tokenContent) & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0; 154 } 155 156 // Returns true if the content data belongs to a Unique Token 157 function isSingle(bytes32 _tokenContent) private pure returns(bool) { 158 return uint256(_tokenContent) & 0x4000000000000000000000000000000000000000000000000000000000000000 > 0; 159 } 160 161 // Reassemble unique token key from indexed token id 162 function getDigest(bytes32 _truncatedId) public view returns (bytes32) { 163 bytes32 digest; 164 165 digest = mintedToken[_truncatedId]; 166 require(isActive(digest)); 167 168 if (isSingle(digest)) { 169 return _truncatedId; 170 } 171 172 digest &= 0x00ffffffffffffffff0000000000000000000000000000000000000000000000; 173 digest >>= 184; 174 digest |= _truncatedId & 0xffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000; 175 return digest; 176 } 177 178 // Allocate tokens for minting. 179 // if count is set to 0, only a single unique token can be minted. 180 // if count is set a negative number, the token will be unbounded (may be capped later with setCap). 181 function allocate(bytes32 content, int48 count) public returns (bool) { 182 uint256 l; 183 require(msg.sender == owner || writer[msg.sender], 'ERR_ACCESS'); 184 185 tokenSpec memory _token; 186 187 l = token[content].length; 188 if (l > 0) { 189 require(token[content][0].count > 0); 190 } 191 192 if (count == 0) { 193 _token.capped = true; 194 } else if (count > 0) { 195 _token.count = uint48(count); 196 _token.capped = true; 197 } 198 token[content].push(_token); 199 tokens.push(content); 200 201 emit Allocate(msg.sender, _token.count, _token.capped, content); 202 return true; 203 } 204 205 // Find the token batch which contains the given index. 206 // Search scope can be controlled using the _startAt and _endAt properties. 207 // function batchOf(bytes32 _content, uint256 _superIndex, uint256 _startAt) public view returns(int256) { 208 // for (uint256 i = _startAt; i < token[_content].length; i++) { 209 // if (token[_content][i].cumulativeCount > uint128(_superIndex)) { 210 // return int256(i); 211 // } 212 // } 213 // return -1; 214 // } 215 216 // Mint a unique token. The method will fail if the token was allocated as a batch. 217 function mintToBytes(address _recipient, bytes32 _content) public returns (bytes32) { 218 uint256 right; 219 uint256 tokenId; 220 uint256 _balance; 221 222 require(msg.sender == owner || writer[msg.sender]); 223 require(token[_content].length == 1); 224 require(token[_content][0].count == 0); 225 require(mintedToken[_content] == bytes32(0x00)); 226 227 right = uint160(_recipient); 228 right |= (3 << 254); 229 mintedToken[_content] = bytes32(right); 230 231 tokenId = uint256(_content); 232 _balance = balance[_recipient]; 233 ownerIndexReverse[tokenId] = _balance; 234 tokenOfOwnerByIndex[_recipient][_balance] = tokenId; 235 balance[_recipient] += 1; 236 tokenByIndex.push(tokenId); //int256(_content)); 237 238 emit Mint(msg.sender, _recipient, tokenId); 239 240 return _content; 241 } 242 243 // Proxy for mintToBytes 244 // Implements Minter 245 function mintTo(address _recipient, uint256 _contentNumeric) public returns (bytes32) { 246 bytes32 _content; 247 _content = bytes32(_contentNumeric); 248 return mintToBytes(_recipient, _content); 249 } 250 251 // Implements Minter 252 function mint(address _recipient, uint256 _tokenId, bytes calldata _data) public { 253 _data; 254 mintTo(_recipient, _tokenId); 255 } 256 257 // Implements Minter 258 function safeMint(address _recipient, uint256 _tokenId, bytes calldata _data) public { 259 _data; 260 mintTo(_recipient, _tokenId); 261 } 262 263 // Apply the token owner to the token content data. 264 function setTokenOwner(uint256 _tokenId, address _newOwner) private { 265 uint256 _data; 266 bytes32 _k; 267 268 _k = bytes32(_tokenId); 269 270 _data = uint256(mintedToken[_k]); 271 require(_data != 0); 272 273 _data &= 0xffffffffffffffffffffffff0000000000000000000000000000000000000000; 274 _data |= uint160(_newOwner); 275 mintedToken[_k] = bytes32(_data); 276 } 277 278 // Apply cap on unbounded token 279 // if cap value is set to 0, cap will be set on the current count. 280 function setCap(bytes32 _content, uint16 _batch, uint48 _cap) public { 281 tokenSpec storage spec; 282 283 spec = token[_content][uint256(_batch)]; 284 require(!spec.sparse, 'ERR_SPARSE'); 285 require(!spec.capped, 'ERR_CAPPED'); 286 if (_cap == 0) { 287 _cap = spec.cursor; 288 } 289 require(_cap >= spec.count, 'ERR_CAP_LOW'); 290 spec.count = _cap; 291 spec.capped = true; 292 } 293 294 // Mint a token from a batch. 295 // Will fail if: 296 // * All tokens in the batch have already been minted 297 // * One or more tokens have been minted out of sequential order (see mintExactFromBatchTo) 298 // 299 // If the token was allocated as a single token (which has not yet been minted), 300 // this method will transparently alias to mintTo 301 function mintFromBatchTo(address _recipient, bytes32 _content, uint16 _batch) public returns (bytes32) { 302 tokenSpec storage spec; 303 304 spec = token[_content][uint256(_batch)]; 305 306 require(!spec.sparse, 'ERR_SPARSE'); 307 require(msg.sender == owner || writer[msg.sender], 'ERR_ACCESS'); 308 if (_batch == 0 && spec.count == 0 && spec.capped) { 309 spec.cursor += 1; 310 return mintToBytes(_recipient, _content); 311 } 312 if (spec.capped) { 313 require(spec.cursor < spec.count); 314 } 315 return mintBatchCore(_recipient, _content, _batch, spec.cursor, spec); 316 } 317 318 319 // Mint a token at a specific index of a batch 320 // If the index is not the next sequential index in the batch, the token will be marked as sparse. 321 // Sparse tokens cannot thereafter be minted using mintFromBatchTo 322 // The method will fail if the token at the specified index has already been minted, or if the index is out of bounds of the batch. 323 // This method cannot be used to mint a unique token or an unbounded token. 324 function mintExactFromBatchTo(address _recipient, bytes32 _content, uint16 _batch, uint48 _index) public returns (bytes32) { 325 tokenSpec storage spec; 326 327 spec = token[_content][_batch]; 328 require(msg.sender == owner || writer[msg.sender], 'ERR_ACCESS'); 329 require(spec.count > 0); 330 require(spec.capped); 331 require(_index < spec.count); 332 return mintBatchCore(_recipient, _content, _batch, _index, spec); 333 } 334 335 // Common code path for both batch mint methods. 336 function mintBatchCore(address _recipient, bytes32 _content, uint16 _batch, uint48 _index, tokenSpec storage _spec) private returns (bytes32) { 337 uint256 left; 338 uint256 right; 339 bytes32 k; 340 uint256 _balance; 341 342 left = uint256(_content) & 0xffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000; 343 left |= ((_batch & 0xffffffffffffffff) << 48); 344 left |= _index; 345 k = bytes32(left); 346 347 require(mintedToken[k] == bytes32(0x00)); 348 349 if (!_spec.sparse) { 350 if (_index != _spec.cursor) { 351 _spec.sparse = true; 352 } 353 } 354 355 right = uint256(_content) & ((1 << 64) - 1); 356 right <<= 184; 357 right |= (1 << 255); 358 right |= uint160(_recipient); 359 360 _spec.cursor += 1; 361 if (!_spec.capped) { 362 _spec.count += 1; 363 } 364 mintedToken[k] = bytes32(right); 365 366 _balance = balance[_recipient]; 367 ownerIndexReverse[left] = _balance; 368 tokenOfOwnerByIndex[_recipient][_balance] = left; 369 370 balance[_recipient] += 1; 371 tokenByIndex.push(left); 372 373 emit Mint(msg.sender, _recipient, left); 374 375 return k; 376 } 377 378 // Implements ERC721 379 function balanceOf(address _owner) external view returns (uint256) { 380 return balance[_owner]; 381 } 382 383 // Implements ERC721 384 function setApprovalForAll(address _operator, bool _approved) external { 385 if (_approved) { 386 require(tokenOperator[msg.sender] == address(0)); // save a few bucks in gas if fail 387 tokenOperator[msg.sender] = _operator; 388 } else { 389 require(tokenOperator[msg.sender] != address(0)); 390 tokenOperator[msg.sender] = address(0); 391 } 392 emit ApprovalForAll(msg.sender, _operator, _approved); 393 } 394 395 // Implements ERC721 396 function getApproved(uint256 _tokenId) external view returns (address) { 397 return tokenAllowance[_tokenId]; 398 } 399 400 // Implements ERC721 401 function isApprovedForAll(address _owner, address _operator) external view returns (bool) { 402 return tokenOperator[_owner] == _operator; 403 } 404 405 // Implements ERC721 406 function ownerOf(uint256 _tokenId) external view returns (address) { 407 bytes32 _tokenContent; 408 409 _tokenContent = mintedToken[bytes32(_tokenId)]; 410 return address(bytes20(_tokenContent << 96)); 411 } 412 413 // Common code path for transfer methods 414 function transferCore(address _from, address _to, uint256 _tokenId) internal { 415 address currentTokenOwner; 416 uint256 reverseIndex; 417 uint256 currentIndex; 418 419 currentTokenOwner = this.ownerOf(_tokenId); 420 421 require(currentTokenOwner == _from); 422 if (_from != msg.sender) { 423 require(tokenAllowance[_tokenId] == msg.sender || tokenOperator[currentTokenOwner] == msg.sender); 424 } 425 426 tokenAllowance[_tokenId] = address(0); 427 setTokenOwner(_tokenId, _to); 428 reverseIndex = ownerIndexReverse[_tokenId]; 429 currentIndex = balance[_from] - 1; 430 if (currentIndex > reverseIndex) { 431 tokenOfOwnerByIndex[_from][reverseIndex] = tokenOfOwnerByIndex[_from][currentIndex]; 432 } 433 tokenOfOwnerByIndex[_from][currentIndex] = uint256(0); 434 435 currentIndex = balance[_to]; 436 tokenOfOwnerByIndex[_to][currentIndex] = _tokenId; 437 438 balance[_from] -= 1; 439 balance[_to] += 1; 440 } 441 442 // Implements ERC721 443 function transferFrom(address _from, address _to, uint256 _tokenId) external payable { 444 transferCore(_from, _to, _tokenId); 445 emit Transfer(_from, _to, _tokenId); 446 } 447 448 // Implements ERC721 449 function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) external payable { 450 transferCore(_from, _to, _tokenId); 451 emit Transfer(_from, _to, _tokenId); 452 emit TransferWithData(_from, _to, _tokenId, bytes32(_data)); 453 } 454 455 // Implements ERC721 456 function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable { 457 transferCore(_from, _to, _tokenId); 458 emit Transfer(_from, _to, _tokenId); 459 } 460 461 // Allow mutable explicit url base 462 function setBaseURL(string memory _baseString) public { 463 bytes memory _base; 464 uint256 l; 465 require(msg.sender == owner); 466 467 _base = bytes(_baseString); 468 l = _base.length; 469 if (_base[l-1] != 0x2f) { 470 l++; 471 } 472 baseURL = new bytes(l); 473 for (uint256 i = 0; i < _base.length; i++) { 474 baseURL[i] = _base[i]; 475 } 476 if (l != _base.length) { 477 baseURL[_base.length] = "/"; 478 } 479 } 480 481 // Implements Locator 482 function toURL(bytes memory _data) public view returns(string memory) { 483 bytes memory out; 484 bytes memory _hexDigest; 485 uint256 c; 486 487 _hexDigest = toHex(_data); 488 489 c = baseURL.length; 490 out = new bytes(_hexDigest.length + c); 491 492 for (uint256 i = 0; i < c; i++) { 493 out[i] = baseURL[i]; 494 } 495 for (uint256 i = 0; i < _hexDigest.length; i++) { 496 out[c] = _hexDigest[i]; 497 c++; 498 } 499 return string(out); 500 } 501 502 // TODO: move to internal library method 503 // bytes to hex conversion 504 function toHex(bytes memory _data) public pure returns(bytes memory) { 505 bytes memory out; 506 uint8 t; 507 uint256 c; 508 509 out = new bytes(_data.length * 2); 510 c = 0; 511 for (uint256 i = 0; i < 32; i++) { 512 t = (uint8(_data[i]) & 0xf0) >> 4; 513 if (t < 10) { 514 out[c] = bytes1(t + 0x30); 515 } else { 516 out[c] = bytes1(t + 0x57); 517 } 518 t = uint8(_data[i]) & 0x0f; 519 if (t < 10) { 520 out[c+1] = bytes1(t + 0x30); 521 } else { 522 out[c+1] = bytes1(t + 0x57); 523 } 524 c += 2; 525 } 526 return out; 527 } 528 529 // Implements ERC721Metadata 530 function tokenURI(uint256 _tokenId) public view returns (string memory) { 531 bytes32 _tokenIdBytesFixed; 532 bytes memory _tokenIdBytes; 533 534 _tokenIdBytesFixed = bytes32(_tokenId); 535 536 // If not direct match, check if it is a batch. 537 // Fail if still not found (length 0). 538 if (token[_tokenIdBytesFixed].length == 0) { 539 _tokenIdBytesFixed = getDigest(_tokenIdBytesFixed); 540 } 541 require(token[_tokenIdBytesFixed].length > 0); 542 543 _tokenIdBytes = new bytes(32); 544 for (uint256 i = 0; i < 32; i++) { 545 _tokenIdBytes[i] = _tokenIdBytesFixed[i]; 546 } 547 548 return toURL(_tokenIdBytes); 549 } 550 551 // EIP-165 552 function supportsInterface(bytes4 interfaceID) external pure returns (bool) { 553 uint32 interfaceN; 554 uint32 masked; 555 556 interfaceN = uint32(interfaceID); 557 558 // EIP165 interface id 559 if (uint32(interfaceID) == 0x01ffc9a7) { 560 return true; 561 } 562 563 for (uint256 i = 0; i < 256; i += 32) { 564 masked = uint32((interfaces >> i) & 0xffffffff); 565 if (masked == 0) { 566 return false; 567 } 568 if (interfaceN == masked) { 569 return true; 570 } 571 } 572 573 return false; 574 } 575 576 // Implements ERC721Enumerable 577 function totalSupply() public view returns(uint256) { 578 return tokenByIndex.length; 579 } 580 581 // Add a multicodec that can later be set as current codec 582 function addMultiCodec(uint8 _length, uint64 _codecId, string memory _uriPrefix) public { 583 bytes memory prefixBytes; 584 585 prefixBytes = bytes(_uriPrefix); 586 require(prefixBytes.length <= 16, 'ERR_PREFIX_TOO_LONG'); 587 MultiHash memory _hsh; 588 uint8 c; 589 590 c = 7; 591 while (c >= 0) { 592 uint64 mask = uint64(0xff << (c * 8)); 593 if ((mask & _codecId) > 0) { 594 break; 595 } 596 c--; 597 } 598 _hsh.codecRLength = c + 1; 599 _hsh.codec = bytes8(_codecId << ((7 - c) * 8)); 600 _hsh.prefixRLength = uint8(prefixBytes.length); 601 _hsh.prefix = bytes16(prefixBytes); 602 _hsh.l = _length; 603 604 multiHash[uint256(_codecId)] = _hsh; 605 } 606 607 // Generate a multihash from the given digest and current selected multicodec 608 // Implements Digest 609 function encodeDigest(bytes memory _digest, uint256 _codec) public view returns(bytes memory) { 610 MultiHash storage m; 611 bytes memory r; 612 613 m = multiHash[_codec]; 614 r = new bytes(_digest.length + m.l + m.codecRLength); 615 616 uint256 i = 0; 617 for (i; i < m.codecRLength; i++) { 618 r[i] = m.codec[i]; 619 } 620 r[i] = bytes1(m.l); 621 i++; 622 for (uint256 j = 0; j < _digest.length; j++) { 623 r[i+j] = _digest[j]; 624 } 625 626 return r; 627 } 628 629 // Implements Digest 630 function encodeDigest(bytes memory _digest) public view returns(bytes memory) { 631 return encodeDigest(_digest, defaultDigestEncoding); 632 } 633 634 // Generate a URI representing the digest and the string prefix representation 635 // of the currently selected multicodec 636 // Implements Locator 637 function toURI(bytes memory _digest) public view returns(string memory) { 638 MultiHash storage m; 639 640 bytes memory codecString; 641 bytes memory digestHex; 642 uint256 l; 643 644 digestHex = toHex(_digest); 645 m = multiHash[defaultDigestEncoding]; 646 l = m.prefixRLength; 647 codecString = new bytes(l + digestHex.length + 1); 648 for (uint256 i = 0; i < l; i++) { 649 codecString[i] = m.prefix[i]; 650 } 651 codecString[l] = 0x3a; 652 l++; 653 654 for (uint256 i = 0; i < digestHex.length; i++) { 655 codecString[l+i] = digestHex[i]; 656 } 657 return string(codecString); 658 659 } 660 661 662 // Set the current multicodec to use for multihash generation 663 function setMsgCodec(uint256 _codec) public { 664 MultiHash storage _hsh; 665 666 _hsh = multiHash[_codec]; 667 require(_hsh.l > 0); 668 669 defaultDigestEncoding = _codec; 670 currentMsg = new bytes(_hsh.l); 671 672 //emit Msg(getMsg()); 673 } 674 675 // Set the latest pesistent message on contract 676 function setMsg(bytes memory _digest) public { 677 MultiHash storage _hsh; 678 679 _hsh = multiHash[defaultDigestEncoding]; 680 require(_digest.length == _hsh.l); 681 682 currentMsg = _digest; 683 emit Msg(getMsg()); 684 } 685 686 // Return a multihash of the latest persistent message 687 // Implements Msg 688 function getMsg() public view returns(bytes memory) { 689 return encodeDigest(currentMsg); 690 } 691 }