github.com/iotexproject/iotex-core@v1.14.1-rc1/tools/executiontester/blockchain/erc721.sol (about) 1 pragma solidity 0.4.24; 2 3 /* 4 ERC-721 NIFTY remote hackathon for: 5 https://github.com/austintgriffith/nifties-vs-nfties 6 7 Austin Thomas Griffith - https://austingriffith.com 8 9 This Token is for the Nfties (no eye in Nfties) monsters 10 11 They have the following metadata: 12 struct Token{ 13 uint8 body; 14 uint8 feet; 15 uint8 head; 16 uint8 mouth; 17 uint8 extra; 18 uint64 birthBlock; 19 } 20 */ 21 22 23 24 25 26 27 /** 28 * @title ERC165 29 * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md 30 */ 31 interface ERC165 { 32 33 /** 34 * @notice Query if a contract implements an interface 35 * @param _interfaceId The interface identifier, as specified in ERC-165 36 * @dev Interface identification is specified in ERC-165. This function 37 * uses less than 30,000 gas. 38 */ 39 function supportsInterface(bytes4 _interfaceId) 40 external 41 view 42 returns (bool); 43 } 44 45 46 47 48 /** 49 * @title SupportsInterfaceWithLookup 50 * @author Matt Condon (@shrugs) 51 * @dev Implements ERC165 using a lookup table. 52 */ 53 contract SupportsInterfaceWithLookup is ERC165 { 54 bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7; 55 /** 56 * 0x01ffc9a7 === 57 * bytes4(keccak256('supportsInterface(bytes4)')) 58 */ 59 60 /** 61 * @dev a mapping of interface id to whether or not it's supported 62 */ 63 mapping(bytes4 => bool) internal supportedInterfaces; 64 65 /** 66 * @dev A contract implementing SupportsInterfaceWithLookup 67 * implement ERC165 itself 68 */ 69 constructor() 70 public 71 { 72 _registerInterface(InterfaceId_ERC165); 73 } 74 75 /** 76 * @dev implement supportsInterface(bytes4) using a lookup table 77 */ 78 function supportsInterface(bytes4 _interfaceId) 79 external 80 view 81 returns (bool) 82 { 83 return supportedInterfaces[_interfaceId]; 84 } 85 86 /** 87 * @dev private method for registering an interface 88 */ 89 function _registerInterface(bytes4 _interfaceId) 90 internal 91 { 92 require(_interfaceId != 0xffffffff); 93 supportedInterfaces[_interfaceId] = true; 94 } 95 } 96 97 98 /** 99 * @title ERC721 Non-Fungible Token Standard basic interface 100 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 101 */ 102 contract ERC721Basic is ERC165 { 103 104 bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd; 105 /* 106 * 0x80ac58cd === 107 * bytes4(keccak256('balanceOf(address)')) ^ 108 * bytes4(keccak256('ownerOf(uint256)')) ^ 109 * bytes4(keccak256('approve(address,uint256)')) ^ 110 * bytes4(keccak256('getApproved(uint256)')) ^ 111 * bytes4(keccak256('setApprovalForAll(address,bool)')) ^ 112 * bytes4(keccak256('isApprovedForAll(address,address)')) ^ 113 * bytes4(keccak256('transferFrom(address,address,uint256)')) ^ 114 * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^ 115 * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) 116 */ 117 118 bytes4 internal constant InterfaceId_ERC721Exists = 0x4f558e79; 119 /* 120 * 0x4f558e79 === 121 * bytes4(keccak256('exists(uint256)')) 122 */ 123 124 bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63; 125 /** 126 * 0x780e9d63 === 127 * bytes4(keccak256('totalSupply()')) ^ 128 * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ 129 * bytes4(keccak256('tokenByIndex(uint256)')) 130 */ 131 132 bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f; 133 /** 134 * 0x5b5e139f === 135 * bytes4(keccak256('name()')) ^ 136 * bytes4(keccak256('symbol()')) ^ 137 * bytes4(keccak256('tokenURI(uint256)')) 138 */ 139 140 event Transfer( 141 address indexed _from, 142 address indexed _to, 143 uint256 indexed _tokenId 144 ); 145 event Approval( 146 address indexed _owner, 147 address indexed _approved, 148 uint256 indexed _tokenId 149 ); 150 event ApprovalForAll( 151 address indexed _owner, 152 address indexed _operator, 153 bool _approved 154 ); 155 156 function balanceOf(address _owner) public view returns (uint256 _balance); 157 function ownerOf(uint256 _tokenId) public view returns (address _owner); 158 function exists(uint256 _tokenId) public view returns (bool _exists); 159 160 function approve(address _to, uint256 _tokenId) public; 161 function getApproved(uint256 _tokenId) 162 public view returns (address _operator); 163 164 function setApprovalForAll(address _operator, bool _approved) public; 165 function isApprovedForAll(address _owner, address _operator) 166 public view returns (bool); 167 168 function transferFrom(address _from, address _to, uint256 _tokenId) public; 169 function safeTransferFrom(address _from, address _to, uint256 _tokenId) 170 public; 171 172 function safeTransferFrom( 173 address _from, 174 address _to, 175 uint256 _tokenId, 176 bytes _data 177 ) 178 public; 179 } 180 181 182 183 /** 184 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension 185 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 186 */ 187 contract ERC721Enumerable is ERC721Basic { 188 function totalSupply() public view returns (uint256); 189 function tokenOfOwnerByIndex( 190 address _owner, 191 uint256 _index 192 ) 193 public 194 view 195 returns (uint256 _tokenId); 196 197 function tokenByIndex(uint256 _index) public view returns (uint256); 198 } 199 200 201 /** 202 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 203 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 204 */ 205 contract ERC721Metadata is ERC721Basic { 206 function name() external view returns (string _name); 207 function symbol() external view returns (string _symbol); 208 function tokenURI(uint256 _tokenId) public view returns (string); 209 } 210 211 212 /** 213 * @title ERC-721 Non-Fungible Token Standard, full implementation interface 214 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 215 */ 216 contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata { 217 } 218 219 220 221 222 /** 223 * @title ERC721 token receiver interface 224 * @dev Interface for any contract that wants to support safeTransfers 225 * from ERC721 asset contracts. 226 */ 227 contract ERC721Receiver { 228 /** 229 * @dev Magic value to be returned upon successful reception of an NFT 230 * Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`, 231 * which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` 232 */ 233 bytes4 internal constant ERC721_RECEIVED = 0x150b7a02; 234 235 /** 236 * @notice Handle the receipt of an NFT 237 * @dev The ERC721 smart contract calls this function on the recipient 238 * after a `safetransfer`. This function MAY throw to revert and reject the 239 * transfer. Return of other than the magic value MUST result in the 240 * transaction being reverted. 241 * Note: the contract address is always the message sender. 242 * @param _operator The address which called `safeTransferFrom` function 243 * @param _from The address which previously owned the token 244 * @param _tokenId The NFT identifier which is being transferred 245 * @param _data Additional data with no specified format 246 * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 247 */ 248 function onERC721Received( 249 address _operator, 250 address _from, 251 uint256 _tokenId, 252 bytes _data 253 ) 254 public 255 returns(bytes4); 256 } 257 258 259 260 /** 261 * @title SafeMath 262 * @dev Math operations with safety checks that throw on error 263 */ 264 library SafeMath { 265 266 /** 267 * @dev Multiplies two numbers, throws on overflow. 268 */ 269 function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { 270 // Gas optimization: this is cheaper than asserting 'a' not being zero, but the 271 // benefit is lost if 'b' is also tested. 272 // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 273 if (a == 0) { 274 return 0; 275 } 276 277 c = a * b; 278 assert(c / a == b); 279 return c; 280 } 281 282 /** 283 * @dev Integer division of two numbers, truncating the quotient. 284 */ 285 function div(uint256 a, uint256 b) internal pure returns (uint256) { 286 // assert(b > 0); // Solidity automatically throws when dividing by 0 287 // uint256 c = a / b; 288 // assert(a == b * c + a % b); // There is no case in which this doesn't hold 289 return a / b; 290 } 291 292 /** 293 * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). 294 */ 295 function sub(uint256 a, uint256 b) internal pure returns (uint256) { 296 assert(b <= a); 297 return a - b; 298 } 299 300 /** 301 * @dev Adds two numbers, throws on overflow. 302 */ 303 function add(uint256 a, uint256 b) internal pure returns (uint256 c) { 304 c = a + b; 305 assert(c >= a); 306 return c; 307 } 308 } 309 310 311 312 /** 313 * Utility library of inline functions on addresses 314 */ 315 library AddressUtils { 316 317 /** 318 * Returns whether the target address is a contract 319 * @dev This function will return false if invoked during the constructor of a contract, 320 * as the code is not actually created until after the constructor finishes. 321 * @param addr address to check 322 * @return whether the target address is a contract 323 */ 324 function isContract(address addr) internal view returns (bool) { 325 uint256 size; 326 // XXX Currently there is no better way to check if there is a contract in an address 327 // than to check the size of the code at that address. 328 // See https://ethereum.stackexchange.com/a/14016/36603 329 // for more details about how this works. 330 // TODO Check this again before the Serenity release, because all addresses will be 331 // contracts then. 332 // solium-disable-next-line security/no-inline-assembly 333 assembly { size := extcodesize(addr) } 334 return size > 0; 335 } 336 337 } 338 339 340 341 /** 342 * @title ERC721 Non-Fungible Token Standard basic implementation 343 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 344 */ 345 contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic { 346 347 using SafeMath for uint256; 348 using AddressUtils for address; 349 350 // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 351 // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` 352 bytes4 private constant ERC721_RECEIVED = 0x150b7a02; 353 354 // Mapping from token ID to owner 355 mapping (uint256 => address) internal tokenOwner; 356 357 // Mapping from token ID to approved address 358 mapping (uint256 => address) internal tokenApprovals; 359 360 // Mapping from owner to number of owned token 361 mapping (address => uint256) internal ownedTokensCount; 362 363 // Mapping from owner to operator approvals 364 mapping (address => mapping (address => bool)) internal operatorApprovals; 365 366 constructor() 367 public 368 { 369 // register the supported interfaces to conform to ERC721 via ERC165 370 _registerInterface(InterfaceId_ERC721); 371 _registerInterface(InterfaceId_ERC721Exists); 372 } 373 374 /** 375 * @dev Gets the balance of the specified address 376 * @param _owner address to query the balance of 377 * @return uint256 representing the amount owned by the passed address 378 */ 379 function balanceOf(address _owner) public view returns (uint256) { 380 require(_owner != address(0)); 381 return ownedTokensCount[_owner]; 382 } 383 384 /** 385 * @dev Gets the owner of the specified token ID 386 * @param _tokenId uint256 ID of the token to query the owner of 387 * @return owner address currently marked as the owner of the given token ID 388 */ 389 function ownerOf(uint256 _tokenId) public view returns (address) { 390 address owner = tokenOwner[_tokenId]; 391 require(owner != address(0)); 392 return owner; 393 } 394 395 /** 396 * @dev Returns whether the specified token exists 397 * @param _tokenId uint256 ID of the token to query the existence of 398 * @return whether the token exists 399 */ 400 function exists(uint256 _tokenId) public view returns (bool) { 401 address owner = tokenOwner[_tokenId]; 402 return owner != address(0); 403 } 404 405 /** 406 * @dev Approves another address to transfer the given token ID 407 * The zero address indicates there is no approved address. 408 * There can only be one approved address per token at a given time. 409 * Can only be called by the token owner or an approved operator. 410 * @param _to address to be approved for the given token ID 411 * @param _tokenId uint256 ID of the token to be approved 412 */ 413 function approve(address _to, uint256 _tokenId) public { 414 address owner = ownerOf(_tokenId); 415 require(_to != owner); 416 require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); 417 418 tokenApprovals[_tokenId] = _to; 419 emit Approval(owner, _to, _tokenId); 420 } 421 422 /** 423 * @dev Gets the approved address for a token ID, or zero if no address set 424 * @param _tokenId uint256 ID of the token to query the approval of 425 * @return address currently approved for the given token ID 426 */ 427 function getApproved(uint256 _tokenId) public view returns (address) { 428 return tokenApprovals[_tokenId]; 429 } 430 431 /** 432 * @dev Sets or unsets the approval of a given operator 433 * An operator is allowed to transfer all tokens of the sender on their behalf 434 * @param _to operator address to set the approval 435 * @param _approved representing the status of the approval to be set 436 */ 437 function setApprovalForAll(address _to, bool _approved) public { 438 require(_to != msg.sender); 439 operatorApprovals[msg.sender][_to] = _approved; 440 emit ApprovalForAll(msg.sender, _to, _approved); 441 } 442 443 /** 444 * @dev Tells whether an operator is approved by a given owner 445 * @param _owner owner address which you want to query the approval of 446 * @param _operator operator address which you want to query the approval of 447 * @return bool whether the given operator is approved by the given owner 448 */ 449 function isApprovedForAll( 450 address _owner, 451 address _operator 452 ) 453 public 454 view 455 returns (bool) 456 { 457 return operatorApprovals[_owner][_operator]; 458 } 459 460 /** 461 * @dev Transfers the ownership of a given token ID to another address 462 * Usage of this method is discouraged, use `safeTransferFrom` whenever possible 463 * Requires the msg sender to be the owner, approved, or operator 464 * @param _from current owner of the token 465 * @param _to address to receive the ownership of the given token ID 466 * @param _tokenId uint256 ID of the token to be transferred 467 */ 468 function transferFrom( 469 address _from, 470 address _to, 471 uint256 _tokenId 472 ) 473 public 474 { 475 require(isApprovedOrOwner(msg.sender, _tokenId)); 476 require(_from != address(0)); 477 require(_to != address(0)); 478 479 clearApproval(_from, _tokenId); 480 removeTokenFrom(_from, _tokenId); 481 addTokenTo(_to, _tokenId); 482 483 emit Transfer(_from, _to, _tokenId); 484 } 485 486 /** 487 * @dev Safely transfers the ownership of a given token ID to another address 488 * If the target address is a contract, it must implement `onERC721Received`, 489 * which is called upon a safe transfer, and return the magic value 490 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, 491 * the transfer is reverted. 492 * 493 * Requires the msg sender to be the owner, approved, or operator 494 * @param _from current owner of the token 495 * @param _to address to receive the ownership of the given token ID 496 * @param _tokenId uint256 ID of the token to be transferred 497 */ 498 function safeTransferFrom( 499 address _from, 500 address _to, 501 uint256 _tokenId 502 ) 503 public 504 { 505 // solium-disable-next-line arg-overflow 506 safeTransferFrom(_from, _to, _tokenId, ""); 507 } 508 509 /** 510 * @dev Safely transfers the ownership of a given token ID to another address 511 * If the target address is a contract, it must implement `onERC721Received`, 512 * which is called upon a safe transfer, and return the magic value 513 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, 514 * the transfer is reverted. 515 * Requires the msg sender to be the owner, approved, or operator 516 * @param _from current owner of the token 517 * @param _to address to receive the ownership of the given token ID 518 * @param _tokenId uint256 ID of the token to be transferred 519 * @param _data bytes data to send along with a safe transfer check 520 */ 521 function safeTransferFrom( 522 address _from, 523 address _to, 524 uint256 _tokenId, 525 bytes _data 526 ) 527 public 528 { 529 transferFrom(_from, _to, _tokenId); 530 // solium-disable-next-line arg-overflow 531 require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data)); 532 } 533 534 /** 535 * @dev Returns whether the given spender can transfer a given token ID 536 * @param _spender address of the spender to query 537 * @param _tokenId uint256 ID of the token to be transferred 538 * @return bool whether the msg.sender is approved for the given token ID, 539 * is an operator of the owner, or is the owner of the token 540 */ 541 function isApprovedOrOwner( 542 address _spender, 543 uint256 _tokenId 544 ) 545 internal 546 view 547 returns (bool) 548 { 549 address owner = ownerOf(_tokenId); 550 // Disable solium check because of 551 // https://github.com/duaraghav8/Solium/issues/175 552 // solium-disable-next-line operator-whitespace 553 return ( 554 _spender == owner || 555 getApproved(_tokenId) == _spender || 556 isApprovedForAll(owner, _spender) 557 ); 558 } 559 560 /** 561 * @dev Internal function to mint a new token 562 * Reverts if the given token ID already exists 563 * @param _to The address that will own the minted token 564 * @param _tokenId uint256 ID of the token to be minted by the msg.sender 565 */ 566 function _mint(address _to, uint256 _tokenId) internal { 567 require(_to != address(0)); 568 addTokenTo(_to, _tokenId); 569 emit Transfer(address(0), _to, _tokenId); 570 } 571 572 /** 573 * @dev Internal function to burn a specific token 574 * Reverts if the token does not exist 575 * @param _tokenId uint256 ID of the token being burned by the msg.sender 576 */ 577 function _burn(address _owner, uint256 _tokenId) internal { 578 clearApproval(_owner, _tokenId); 579 removeTokenFrom(_owner, _tokenId); 580 emit Transfer(_owner, address(0), _tokenId); 581 } 582 583 /** 584 * @dev Internal function to clear current approval of a given token ID 585 * Reverts if the given address is not indeed the owner of the token 586 * @param _owner owner of the token 587 * @param _tokenId uint256 ID of the token to be transferred 588 */ 589 function clearApproval(address _owner, uint256 _tokenId) internal { 590 require(ownerOf(_tokenId) == _owner); 591 if (tokenApprovals[_tokenId] != address(0)) { 592 tokenApprovals[_tokenId] = address(0); 593 } 594 } 595 596 /** 597 * @dev Internal function to add a token ID to the list of a given address 598 * @param _to address representing the new owner of the given token ID 599 * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address 600 */ 601 function addTokenTo(address _to, uint256 _tokenId) internal { 602 require(tokenOwner[_tokenId] == address(0)); 603 tokenOwner[_tokenId] = _to; 604 ownedTokensCount[_to] = ownedTokensCount[_to].add(1); 605 } 606 607 /** 608 * @dev Internal function to remove a token ID from the list of a given address 609 * @param _from address representing the previous owner of the given token ID 610 * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address 611 */ 612 function removeTokenFrom(address _from, uint256 _tokenId) internal { 613 require(ownerOf(_tokenId) == _from); 614 ownedTokensCount[_from] = ownedTokensCount[_from].sub(1); 615 tokenOwner[_tokenId] = address(0); 616 } 617 618 /** 619 * @dev Internal function to invoke `onERC721Received` on a target address 620 * The call is not executed if the target address is not a contract 621 * @param _from address representing the previous owner of the given token ID 622 * @param _to target address that will receive the tokens 623 * @param _tokenId uint256 ID of the token to be transferred 624 * @param _data bytes optional data to send along with the call 625 * @return whether the call correctly returned the expected magic value 626 */ 627 function checkAndCallSafeTransfer( 628 address _from, 629 address _to, 630 uint256 _tokenId, 631 bytes _data 632 ) 633 internal 634 returns (bool) 635 { 636 if (!_to.isContract()) { 637 return true; 638 } 639 bytes4 retval = ERC721Receiver(_to).onERC721Received( 640 msg.sender, _from, _tokenId, _data); 641 return (retval == ERC721_RECEIVED); 642 } 643 } 644 645 646 647 648 /** 649 * @title Full ERC721 Token 650 * This implementation includes all the required and some optional functionality of the ERC721 standard 651 * Moreover, it includes approve all functionality using operator terminology 652 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 653 */ 654 contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 { 655 656 // Token name 657 string internal name_; 658 659 // Token symbol 660 string internal symbol_; 661 662 // Mapping from owner to list of owned token IDs 663 mapping(address => uint256[]) internal ownedTokens; 664 665 // Mapping from token ID to index of the owner tokens list 666 mapping(uint256 => uint256) internal ownedTokensIndex; 667 668 // Array with all token ids, used for enumeration 669 uint256[] internal allTokens; 670 671 // Mapping from token id to position in the allTokens array 672 mapping(uint256 => uint256) internal allTokensIndex; 673 674 // Optional mapping for token URIs 675 mapping(uint256 => string) internal tokenURIs; 676 677 /** 678 * @dev Constructor function 679 */ 680 constructor(string _name, string _symbol) public { 681 name_ = _name; 682 symbol_ = _symbol; 683 684 // register the supported interfaces to conform to ERC721 via ERC165 685 _registerInterface(InterfaceId_ERC721Enumerable); 686 _registerInterface(InterfaceId_ERC721Metadata); 687 } 688 689 /** 690 * @dev Gets the token name 691 * @return string representing the token name 692 */ 693 function name() external view returns (string) { 694 return name_; 695 } 696 697 /** 698 * @dev Gets the token symbol 699 * @return string representing the token symbol 700 */ 701 function symbol() external view returns (string) { 702 return symbol_; 703 } 704 705 /** 706 * @dev Returns an URI for a given token ID 707 * Throws if the token ID does not exist. May return an empty string. 708 * @param _tokenId uint256 ID of the token to query 709 */ 710 function tokenURI(uint256 _tokenId) public view returns (string) { 711 require(exists(_tokenId)); 712 return tokenURIs[_tokenId]; 713 } 714 715 /** 716 * @dev Gets the token ID at a given index of the tokens list of the requested owner 717 * @param _owner address owning the tokens list to be accessed 718 * @param _index uint256 representing the index to be accessed of the requested tokens list 719 * @return uint256 token ID at the given index of the tokens list owned by the requested address 720 */ 721 function tokenOfOwnerByIndex( 722 address _owner, 723 uint256 _index 724 ) 725 public 726 view 727 returns (uint256) 728 { 729 require(_index < balanceOf(_owner)); 730 return ownedTokens[_owner][_index]; 731 } 732 733 /** 734 * @dev Gets the total amount of tokens stored by the contract 735 * @return uint256 representing the total amount of tokens 736 */ 737 function totalSupply() public view returns (uint256) { 738 return allTokens.length; 739 } 740 741 /** 742 * @dev Gets the token ID at a given index of all the tokens in this contract 743 * Reverts if the index is greater or equal to the total number of tokens 744 * @param _index uint256 representing the index to be accessed of the tokens list 745 * @return uint256 token ID at the given index of the tokens list 746 */ 747 function tokenByIndex(uint256 _index) public view returns (uint256) { 748 require(_index < totalSupply()); 749 return allTokens[_index]; 750 } 751 752 /** 753 * @dev Internal function to set the token URI for a given token 754 * Reverts if the token ID does not exist 755 * @param _tokenId uint256 ID of the token to set its URI 756 * @param _uri string URI to assign 757 */ 758 function _setTokenURI(uint256 _tokenId, string _uri) internal { 759 require(exists(_tokenId)); 760 tokenURIs[_tokenId] = _uri; 761 } 762 763 /** 764 * @dev Internal function to add a token ID to the list of a given address 765 * @param _to address representing the new owner of the given token ID 766 * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address 767 */ 768 function addTokenTo(address _to, uint256 _tokenId) internal { 769 super.addTokenTo(_to, _tokenId); 770 uint256 length = ownedTokens[_to].length; 771 ownedTokens[_to].push(_tokenId); 772 ownedTokensIndex[_tokenId] = length; 773 } 774 775 /** 776 * @dev Internal function to remove a token ID from the list of a given address 777 * @param _from address representing the previous owner of the given token ID 778 * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address 779 */ 780 function removeTokenFrom(address _from, uint256 _tokenId) internal { 781 super.removeTokenFrom(_from, _tokenId); 782 783 // To prevent a gap in the array, we store the last token in the index of the token to delete, and 784 // then delete the last slot. 785 uint256 tokenIndex = ownedTokensIndex[_tokenId]; 786 uint256 lastTokenIndex = ownedTokens[_from].length.sub(1); 787 uint256 lastToken = ownedTokens[_from][lastTokenIndex]; 788 789 ownedTokens[_from][tokenIndex] = lastToken; 790 ownedTokens[_from].length--; // This also deletes the contents at the last position of the array 791 792 // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to 793 // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping 794 // the lastToken to the first position, and then dropping the element placed in the last position of the list 795 796 ownedTokensIndex[_tokenId] = 0; 797 ownedTokensIndex[lastToken] = tokenIndex; 798 } 799 800 /** 801 * @dev Internal function to mint a new token 802 * Reverts if the given token ID already exists 803 * @param _to address the beneficiary that will own the minted token 804 * @param _tokenId uint256 ID of the token to be minted by the msg.sender 805 */ 806 function _mint(address _to, uint256 _tokenId) internal { 807 super._mint(_to, _tokenId); 808 809 allTokensIndex[_tokenId] = allTokens.length; 810 allTokens.push(_tokenId); 811 } 812 813 /** 814 * @dev Internal function to burn a specific token 815 * Reverts if the token does not exist 816 * @param _owner owner of the token to burn 817 * @param _tokenId uint256 ID of the token being burned by the msg.sender 818 */ 819 function _burn(address _owner, uint256 _tokenId) internal { 820 super._burn(_owner, _tokenId); 821 822 // Clear metadata (if any) 823 if (bytes(tokenURIs[_tokenId]).length != 0) { 824 delete tokenURIs[_tokenId]; 825 } 826 827 // Reorg all tokens array 828 uint256 tokenIndex = allTokensIndex[_tokenId]; 829 uint256 lastTokenIndex = allTokens.length.sub(1); 830 uint256 lastToken = allTokens[lastTokenIndex]; 831 832 allTokens[tokenIndex] = lastToken; 833 allTokens[lastTokenIndex] = 0; 834 835 allTokens.length--; 836 allTokensIndex[_tokenId] = 0; 837 allTokensIndex[lastToken] = tokenIndex; 838 } 839 840 } 841 842 843 contract Nfties is ERC721Token { 844 845 constructor() public ERC721Token("Nfties","NFTIES") { } 846 847 struct Token{ 848 uint8 body; 849 uint8 feet; 850 uint8 head; 851 uint8 mouth; 852 uint8 extra; 853 uint64 birthBlock; 854 } 855 856 Token[] private tokens; 857 858 //Anyone can pay the gas to create their very own Tester token 859 function create() public returns (uint256 _tokenId) { 860 861 bytes32 sudoRandomButTotallyPredictable = keccak256(abi.encodePacked(totalSupply(),blockhash(block.number - 1))); 862 uint8 body = (uint8(sudoRandomButTotallyPredictable[0])%5)+1; 863 uint8 feet = (uint8(sudoRandomButTotallyPredictable[1])%5)+1; 864 uint8 head = (uint8(sudoRandomButTotallyPredictable[2])%5)+1; 865 uint8 mouth = (uint8(sudoRandomButTotallyPredictable[3])%5)+1; 866 uint8 extra = (uint8(sudoRandomButTotallyPredictable[4])%5)+1; 867 868 //this is about half of all the gas it takes because I'm doing some string manipulation 869 //I could skip this, or make it way more efficient but the is just a silly hackathon project 870 string memory tokenUri = createTokenUri(body,feet,head,mouth,extra); 871 872 Token memory _newToken = Token({ 873 body: body, 874 feet: feet, 875 head: head, 876 mouth: mouth, 877 extra: extra, 878 birthBlock: uint64(block.number) 879 }); 880 _tokenId = tokens.push(_newToken) - 1; 881 _mint(msg.sender,_tokenId); 882 _setTokenURI(_tokenId, tokenUri); 883 emit Create(_tokenId,msg.sender,body,feet,head,mouth,extra,_newToken.birthBlock,tokenUri); 884 return _tokenId; 885 } 886 function createTo(address _owner,uint256 _tokenId) public{ 887 string memory tokenUri ="test"; 888 _mint(_owner,_tokenId); 889 _setTokenURI(_tokenId, tokenUri); 890 } 891 event Create( 892 uint _id, 893 address indexed _owner, 894 uint8 _body, 895 uint8 _feet, 896 uint8 _head, 897 uint8 _mouth, 898 uint8 _extra, 899 uint64 _birthBlock, 900 string _uri 901 ); 902 903 //Get any token metadata by passing in the ID 904 function get(uint256 _id) public view returns (address owner,uint8 body,uint8 feet,uint8 head,uint8 mouth,uint8 extra,uint64 birthBlock) { 905 return ( 906 tokenOwner[_id], 907 tokens[_id].body, 908 tokens[_id].feet, 909 tokens[_id].head, 910 tokens[_id].mouth, 911 tokens[_id].extra, 912 tokens[_id].birthBlock 913 ); 914 } 915 916 function tokensOfOwner(address _owner) public view returns(uint256[]) { 917 return ownedTokens[_owner]; 918 } 919 920 function createTokenUri(uint8 body,uint8 feet,uint8 head,uint8 mouth,uint8 extra) internal returns (string){ 921 string memory uri = "https://nfties.io/tokens/nfties-"; 922 uri = appendUint8ToString(uri,body); 923 uri = strConcat(uri,"-"); 924 uri = appendUint8ToString(uri,feet); 925 uri = strConcat(uri,"-"); 926 uri = appendUint8ToString(uri,head); 927 uri = strConcat(uri,"-"); 928 uri = appendUint8ToString(uri,mouth); 929 uri = strConcat(uri,"-"); 930 uri = appendUint8ToString(uri,extra); 931 uri = strConcat(uri,".png"); 932 return uri; 933 } 934 935 function appendUint8ToString(string inStr, uint8 v) internal constant returns (string str) { 936 uint maxlength = 100; 937 bytes memory reversed = new bytes(maxlength); 938 uint i = 0; 939 while (v != 0) { 940 uint remainder = v % 10; 941 v = v / 10; 942 reversed[i++] = byte(48 + remainder); 943 } 944 bytes memory inStrb = bytes(inStr); 945 bytes memory s = new bytes(inStrb.length + i); 946 uint j; 947 for (j = 0; j < inStrb.length; j++) { 948 s[j] = inStrb[j]; 949 } 950 for (j = 0; j < i; j++) { 951 s[j + inStrb.length] = reversed[i - 1 - j]; 952 } 953 str = string(s); 954 } 955 956 function strConcat(string _a, string _b) internal pure returns (string) { 957 bytes memory _ba = bytes(_a); 958 bytes memory _bb = bytes(_b); 959 string memory ab = new string(_ba.length + _bb.length); 960 bytes memory bab = bytes(ab); 961 uint k = 0; 962 for (uint i = 0; i < _ba.length; i++) bab[k++] = _ba[i]; 963 for (i = 0; i < _bb.length; i++) bab[k++] = _bb[i]; 964 return string(bab); 965 } 966 967 }