ERC721Token.sol 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. pragma solidity ^0.4.18;
  2. import "./ERC721.sol";
  3. import "../math/SafeMath.sol";
  4. /**
  5. * @title ERC721Token
  6. * Generic implementation for the required functionality of the ERC721 standard
  7. */
  8. contract ERC721Token is ERC721 {
  9. using SafeMath for uint256;
  10. // Total amount of tokens
  11. uint256 private totalTokens;
  12. // Mapping from token ID to owner
  13. mapping (uint256 => address) private tokenOwner;
  14. // Mapping from token ID to approved address
  15. mapping (uint256 => address) private tokenApprovals;
  16. // Mapping from owner to list of owned token IDs
  17. mapping (address => uint256[]) private ownedTokens;
  18. // Mapping from token ID to index of the owner tokens list
  19. mapping(uint256 => uint256) private ownedTokensIndex;
  20. /**
  21. * @dev Guarantees msg.sender is owner of the given token
  22. * @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender
  23. */
  24. modifier onlyOwnerOf(uint256 _tokenId) {
  25. require(ownerOf(_tokenId) == msg.sender);
  26. _;
  27. }
  28. /**
  29. * @dev Gets the total amount of tokens stored by the contract
  30. * @return uint256 representing the total amount of tokens
  31. */
  32. function totalSupply() public view returns (uint256) {
  33. return totalTokens;
  34. }
  35. /**
  36. * @dev Gets the balance of the specified address
  37. * @param _owner address to query the balance of
  38. * @return uint256 representing the amount owned by the passed address
  39. */
  40. function balanceOf(address _owner) public view returns (uint256) {
  41. return ownedTokens[_owner].length;
  42. }
  43. /**
  44. * @dev Gets the list of tokens owned by a given address
  45. * @param _owner address to query the tokens of
  46. * @return uint256[] representing the list of tokens owned by the passed address
  47. */
  48. function tokensOf(address _owner) public view returns (uint256[]) {
  49. return ownedTokens[_owner];
  50. }
  51. /**
  52. * @dev Gets the owner of the specified token ID
  53. * @param _tokenId uint256 ID of the token to query the owner of
  54. * @return owner address currently marked as the owner of the given token ID
  55. */
  56. function ownerOf(uint256 _tokenId) public view returns (address) {
  57. address owner = tokenOwner[_tokenId];
  58. require(owner != address(0));
  59. return owner;
  60. }
  61. /**
  62. * @dev Gets the approved address to take ownership of a given token ID
  63. * @param _tokenId uint256 ID of the token to query the approval of
  64. * @return address currently approved to take ownership of the given token ID
  65. */
  66. function approvedFor(uint256 _tokenId) public view returns (address) {
  67. return tokenApprovals[_tokenId];
  68. }
  69. /**
  70. * @dev Transfers the ownership of a given token ID to another address
  71. * @param _to address to receive the ownership of the given token ID
  72. * @param _tokenId uint256 ID of the token to be transferred
  73. */
  74. function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
  75. clearApprovalAndTransfer(msg.sender, _to, _tokenId);
  76. }
  77. /**
  78. * @dev Approves another address to claim for the ownership of the given token ID
  79. * @param _to address to be approved for the given token ID
  80. * @param _tokenId uint256 ID of the token to be approved
  81. */
  82. function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
  83. address owner = ownerOf(_tokenId);
  84. require(_to != owner);
  85. if (approvedFor(_tokenId) != 0 || _to != 0) {
  86. tokenApprovals[_tokenId] = _to;
  87. Approval(owner, _to, _tokenId);
  88. }
  89. }
  90. /**
  91. * @dev Claims the ownership of a given token ID
  92. * @param _tokenId uint256 ID of the token being claimed by the msg.sender
  93. */
  94. function takeOwnership(uint256 _tokenId) public {
  95. require(isApprovedFor(_tokenId));
  96. clearApprovalAndTransfer(ownerOf(_tokenId), msg.sender, _tokenId);
  97. }
  98. /**
  99. * @dev Mint token function
  100. * @param _to The address that will own the minted token
  101. * @param _tokenId uint256 ID of the token to be minted by the msg.sender
  102. */
  103. function mint(address _to, uint256 _tokenId) internal {
  104. require(_to != address(0));
  105. addToken(_to, _tokenId);
  106. Transfer(0x0, _to, _tokenId);
  107. }
  108. /**
  109. * @dev Burns a specific token
  110. * @param _tokenId uint256 ID of the token being burned by the msg.sender
  111. */
  112. function burn(uint256 _tokenId) onlyOwnerOf(_tokenId) internal {
  113. if (approvedFor(_tokenId) != 0) {
  114. clearApproval(msg.sender, _tokenId);
  115. }
  116. removeToken(msg.sender, _tokenId);
  117. Transfer(msg.sender, 0x0, _tokenId);
  118. }
  119. /**
  120. * @dev Internal function to clear current approval and transfer the ownership of a given token ID
  121. * @param _from address which you want to send tokens from
  122. * @param _to address which you want to transfer the token to
  123. * @param _tokenId uint256 ID of the token to be transferred
  124. */
  125. function clearApprovalAndTransfer(address _from, address _to, uint256 _tokenId) internal {
  126. require(_to != address(0));
  127. require(_to != ownerOf(_tokenId));
  128. require(ownerOf(_tokenId) == _from);
  129. clearApproval(_from, _tokenId);
  130. removeToken(_from, _tokenId);
  131. addToken(_to, _tokenId);
  132. Transfer(_from, _to, _tokenId);
  133. }
  134. /**
  135. * @dev Internal function to clear current approval of a given token ID
  136. * @param _tokenId uint256 ID of the token to be transferred
  137. */
  138. function clearApproval(address _owner, uint256 _tokenId) internal {
  139. require(ownerOf(_tokenId) == _owner);
  140. tokenApprovals[_tokenId] = 0;
  141. Approval(_owner, 0, _tokenId);
  142. }
  143. /**
  144. * @dev Internal function to add a token ID to the list of a given address
  145. * @param _to address representing the new owner of the given token ID
  146. * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
  147. */
  148. function addToken(address _to, uint256 _tokenId) internal {
  149. require(tokenOwner[_tokenId] == address(0));
  150. tokenOwner[_tokenId] = _to;
  151. uint256 length = balanceOf(_to);
  152. ownedTokens[_to].push(_tokenId);
  153. ownedTokensIndex[_tokenId] = length;
  154. totalTokens = totalTokens.add(1);
  155. }
  156. /**
  157. * @dev Internal function to remove a token ID from the list of a given address
  158. * @param _from address representing the previous owner of the given token ID
  159. * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
  160. */
  161. function removeToken(address _from, uint256 _tokenId) internal {
  162. require(balanceOf(_from) > 0);
  163. require(ownerOf(_tokenId) == _from);
  164. uint256 tokenIndex = ownedTokensIndex[_tokenId];
  165. uint256 lastTokenIndex = balanceOf(_from).sub(1);
  166. uint256 lastToken = ownedTokens[_from][lastTokenIndex];
  167. tokenOwner[_tokenId] = 0;
  168. ownedTokens[_from][tokenIndex] = lastToken;
  169. ownedTokens[_from][lastTokenIndex] = 0;
  170. ownedTokens[_from].length--;
  171. ownedTokensIndex[_tokenId] = 0;
  172. ownedTokensIndex[lastToken] = tokenIndex;
  173. totalTokens = totalTokens.sub(1);
  174. }
  175. /**
  176. * @dev Tells whether the msg.sender is approved for the given token ID or not
  177. * @param _tokenId uint256 ID of the token to query the approval of
  178. * @return bool whether the msg.sender is approved for the given token ID or not
  179. */
  180. function isApprovedFor(uint256 _tokenId) internal view returns (bool) {
  181. return approvedFor(_tokenId) == msg.sender;
  182. }
  183. }