ERC721Token.sol 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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(msg.sender, _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 Tells whether the msg.sender is approved for the given token ID or not
  121. * This function is not private so it can be extended in further implementations like the operatable ERC721
  122. * @param _owner address of the owner to query the approval of
  123. * @param _tokenId uint256 ID of the token to query the approval of
  124. * @return bool whether the msg.sender is approved for the given token ID or not
  125. */
  126. function isApprovedFor(address _owner, uint256 _tokenId) internal view returns (bool) {
  127. return approvedFor(_tokenId) == _owner;
  128. }
  129. /**
  130. * @dev Internal function to clear current approval and transfer the ownership of a given token ID
  131. * @param _from address which you want to send tokens from
  132. * @param _to address which you want to transfer the token to
  133. * @param _tokenId uint256 ID of the token to be transferred
  134. */
  135. function clearApprovalAndTransfer(address _from, address _to, uint256 _tokenId) internal {
  136. require(_to != address(0));
  137. require(_to != ownerOf(_tokenId));
  138. require(ownerOf(_tokenId) == _from);
  139. clearApproval(_from, _tokenId);
  140. removeToken(_from, _tokenId);
  141. addToken(_to, _tokenId);
  142. Transfer(_from, _to, _tokenId);
  143. }
  144. /**
  145. * @dev Internal function to clear current approval of a given token ID
  146. * @param _tokenId uint256 ID of the token to be transferred
  147. */
  148. function clearApproval(address _owner, uint256 _tokenId) private {
  149. require(ownerOf(_tokenId) == _owner);
  150. tokenApprovals[_tokenId] = 0;
  151. Approval(_owner, 0, _tokenId);
  152. }
  153. /**
  154. * @dev Internal function to add a token ID to the list of a given address
  155. * @param _to address representing the new owner of the given token ID
  156. * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
  157. */
  158. function addToken(address _to, uint256 _tokenId) private {
  159. require(tokenOwner[_tokenId] == address(0));
  160. tokenOwner[_tokenId] = _to;
  161. uint256 length = balanceOf(_to);
  162. ownedTokens[_to].push(_tokenId);
  163. ownedTokensIndex[_tokenId] = length;
  164. totalTokens = totalTokens.add(1);
  165. }
  166. /**
  167. * @dev Internal function to remove a token ID from the list of a given address
  168. * @param _from address representing the previous owner of the given token ID
  169. * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
  170. */
  171. function removeToken(address _from, uint256 _tokenId) private {
  172. require(ownerOf(_tokenId) == _from);
  173. uint256 tokenIndex = ownedTokensIndex[_tokenId];
  174. uint256 lastTokenIndex = balanceOf(_from).sub(1);
  175. uint256 lastToken = ownedTokens[_from][lastTokenIndex];
  176. tokenOwner[_tokenId] = 0;
  177. ownedTokens[_from][tokenIndex] = lastToken;
  178. ownedTokens[_from][lastTokenIndex] = 0;
  179. // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
  180. // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
  181. // the lastToken to the first position, and then dropping the element placed in the last position of the list
  182. ownedTokens[_from].length--;
  183. ownedTokensIndex[_tokenId] = 0;
  184. ownedTokensIndex[lastToken] = tokenIndex;
  185. totalTokens = totalTokens.sub(1);
  186. }
  187. }