ERC721BasicToken.sol 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. pragma solidity ^0.4.24;
  2. import "./ERC721Basic.sol";
  3. import "./ERC721Receiver.sol";
  4. import "../../math/SafeMath.sol";
  5. import "../../AddressUtils.sol";
  6. import "../../introspection/SupportsInterfaceWithLookup.sol";
  7. /**
  8. * @title ERC721 Non-Fungible Token Standard basic implementation
  9. * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
  10. */
  11. contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
  12. using SafeMath for uint256;
  13. using AddressUtils for address;
  14. // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
  15. // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
  16. bytes4 private constant ERC721_RECEIVED = 0x150b7a02;
  17. // Mapping from token ID to owner
  18. mapping (uint256 => address) internal tokenOwner;
  19. // Mapping from token ID to approved address
  20. mapping (uint256 => address) internal tokenApprovals;
  21. // Mapping from owner to number of owned token
  22. mapping (address => uint256) internal ownedTokensCount;
  23. // Mapping from owner to operator approvals
  24. mapping (address => mapping (address => bool)) internal operatorApprovals;
  25. constructor()
  26. public
  27. {
  28. // register the supported interfaces to conform to ERC721 via ERC165
  29. _registerInterface(InterfaceId_ERC721);
  30. _registerInterface(InterfaceId_ERC721Exists);
  31. }
  32. /**
  33. * @dev Gets the balance of the specified address
  34. * @param _owner address to query the balance of
  35. * @return uint256 representing the amount owned by the passed address
  36. */
  37. function balanceOf(address _owner) public view returns (uint256) {
  38. require(_owner != address(0));
  39. return ownedTokensCount[_owner];
  40. }
  41. /**
  42. * @dev Gets the owner of the specified token ID
  43. * @param _tokenId uint256 ID of the token to query the owner of
  44. * @return owner address currently marked as the owner of the given token ID
  45. */
  46. function ownerOf(uint256 _tokenId) public view returns (address) {
  47. address owner = tokenOwner[_tokenId];
  48. require(owner != address(0));
  49. return owner;
  50. }
  51. /**
  52. * @dev Returns whether the specified token exists
  53. * @param _tokenId uint256 ID of the token to query the existence of
  54. * @return whether the token exists
  55. */
  56. function exists(uint256 _tokenId) public view returns (bool) {
  57. address owner = tokenOwner[_tokenId];
  58. return owner != address(0);
  59. }
  60. /**
  61. * @dev Approves another address to transfer the given token ID
  62. * The zero address indicates there is no approved address.
  63. * There can only be one approved address per token at a given time.
  64. * Can only be called by the token owner or an approved operator.
  65. * @param _to address to be approved for the given token ID
  66. * @param _tokenId uint256 ID of the token to be approved
  67. */
  68. function approve(address _to, uint256 _tokenId) public {
  69. address owner = ownerOf(_tokenId);
  70. require(_to != owner);
  71. require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
  72. tokenApprovals[_tokenId] = _to;
  73. emit Approval(owner, _to, _tokenId);
  74. }
  75. /**
  76. * @dev Gets the approved address for a token ID, or zero if no address set
  77. * @param _tokenId uint256 ID of the token to query the approval of
  78. * @return address currently approved for the given token ID
  79. */
  80. function getApproved(uint256 _tokenId) public view returns (address) {
  81. return tokenApprovals[_tokenId];
  82. }
  83. /**
  84. * @dev Sets or unsets the approval of a given operator
  85. * An operator is allowed to transfer all tokens of the sender on their behalf
  86. * @param _to operator address to set the approval
  87. * @param _approved representing the status of the approval to be set
  88. */
  89. function setApprovalForAll(address _to, bool _approved) public {
  90. require(_to != msg.sender);
  91. operatorApprovals[msg.sender][_to] = _approved;
  92. emit ApprovalForAll(msg.sender, _to, _approved);
  93. }
  94. /**
  95. * @dev Tells whether an operator is approved by a given owner
  96. * @param _owner owner address which you want to query the approval of
  97. * @param _operator operator address which you want to query the approval of
  98. * @return bool whether the given operator is approved by the given owner
  99. */
  100. function isApprovedForAll(
  101. address _owner,
  102. address _operator
  103. )
  104. public
  105. view
  106. returns (bool)
  107. {
  108. return operatorApprovals[_owner][_operator];
  109. }
  110. /**
  111. * @dev Transfers the ownership of a given token ID to another address
  112. * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
  113. * Requires the msg sender to be the owner, approved, or operator
  114. * @param _from current owner of the token
  115. * @param _to address to receive the ownership of the given token ID
  116. * @param _tokenId uint256 ID of the token to be transferred
  117. */
  118. function transferFrom(
  119. address _from,
  120. address _to,
  121. uint256 _tokenId
  122. )
  123. public
  124. {
  125. require(isApprovedOrOwner(msg.sender, _tokenId));
  126. require(_from != address(0));
  127. require(_to != address(0));
  128. clearApproval(_from, _tokenId);
  129. removeTokenFrom(_from, _tokenId);
  130. addTokenTo(_to, _tokenId);
  131. emit Transfer(_from, _to, _tokenId);
  132. }
  133. /**
  134. * @dev Safely transfers the ownership of a given token ID to another address
  135. * If the target address is a contract, it must implement `onERC721Received`,
  136. * which is called upon a safe transfer, and return the magic value
  137. * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
  138. * the transfer is reverted.
  139. *
  140. * Requires the msg sender to be the owner, approved, or operator
  141. * @param _from current owner of the token
  142. * @param _to address to receive the ownership of the given token ID
  143. * @param _tokenId uint256 ID of the token to be transferred
  144. */
  145. function safeTransferFrom(
  146. address _from,
  147. address _to,
  148. uint256 _tokenId
  149. )
  150. public
  151. {
  152. // solium-disable-next-line arg-overflow
  153. safeTransferFrom(_from, _to, _tokenId, "");
  154. }
  155. /**
  156. * @dev Safely transfers the ownership of a given token ID to another address
  157. * If the target address is a contract, it must implement `onERC721Received`,
  158. * which is called upon a safe transfer, and return the magic value
  159. * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
  160. * the transfer is reverted.
  161. * Requires the msg sender to be the owner, approved, or operator
  162. * @param _from current owner of the token
  163. * @param _to address to receive the ownership of the given token ID
  164. * @param _tokenId uint256 ID of the token to be transferred
  165. * @param _data bytes data to send along with a safe transfer check
  166. */
  167. function safeTransferFrom(
  168. address _from,
  169. address _to,
  170. uint256 _tokenId,
  171. bytes _data
  172. )
  173. public
  174. {
  175. transferFrom(_from, _to, _tokenId);
  176. // solium-disable-next-line arg-overflow
  177. require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
  178. }
  179. /**
  180. * @dev Returns whether the given spender can transfer a given token ID
  181. * @param _spender address of the spender to query
  182. * @param _tokenId uint256 ID of the token to be transferred
  183. * @return bool whether the msg.sender is approved for the given token ID,
  184. * is an operator of the owner, or is the owner of the token
  185. */
  186. function isApprovedOrOwner(
  187. address _spender,
  188. uint256 _tokenId
  189. )
  190. internal
  191. view
  192. returns (bool)
  193. {
  194. address owner = ownerOf(_tokenId);
  195. // Disable solium check because of
  196. // https://github.com/duaraghav8/Solium/issues/175
  197. // solium-disable-next-line operator-whitespace
  198. return (
  199. _spender == owner ||
  200. getApproved(_tokenId) == _spender ||
  201. isApprovedForAll(owner, _spender)
  202. );
  203. }
  204. /**
  205. * @dev Internal function to mint a new token
  206. * Reverts if the given token ID already exists
  207. * @param _to The address that will own the minted token
  208. * @param _tokenId uint256 ID of the token to be minted by the msg.sender
  209. */
  210. function _mint(address _to, uint256 _tokenId) internal {
  211. require(_to != address(0));
  212. addTokenTo(_to, _tokenId);
  213. emit Transfer(address(0), _to, _tokenId);
  214. }
  215. /**
  216. * @dev Internal function to burn a specific token
  217. * Reverts if the token does not exist
  218. * @param _tokenId uint256 ID of the token being burned by the msg.sender
  219. */
  220. function _burn(address _owner, uint256 _tokenId) internal {
  221. clearApproval(_owner, _tokenId);
  222. removeTokenFrom(_owner, _tokenId);
  223. emit Transfer(_owner, address(0), _tokenId);
  224. }
  225. /**
  226. * @dev Internal function to clear current approval of a given token ID
  227. * Reverts if the given address is not indeed the owner of the token
  228. * @param _owner owner of the token
  229. * @param _tokenId uint256 ID of the token to be transferred
  230. */
  231. function clearApproval(address _owner, uint256 _tokenId) internal {
  232. require(ownerOf(_tokenId) == _owner);
  233. if (tokenApprovals[_tokenId] != address(0)) {
  234. tokenApprovals[_tokenId] = address(0);
  235. }
  236. }
  237. /**
  238. * @dev Internal function to add a token ID to the list of a given address
  239. * @param _to address representing the new owner of the given token ID
  240. * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
  241. */
  242. function addTokenTo(address _to, uint256 _tokenId) internal {
  243. require(tokenOwner[_tokenId] == address(0));
  244. tokenOwner[_tokenId] = _to;
  245. ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
  246. }
  247. /**
  248. * @dev Internal function to remove a token ID from the list of a given address
  249. * @param _from address representing the previous owner of the given token ID
  250. * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
  251. */
  252. function removeTokenFrom(address _from, uint256 _tokenId) internal {
  253. require(ownerOf(_tokenId) == _from);
  254. ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
  255. tokenOwner[_tokenId] = address(0);
  256. }
  257. /**
  258. * @dev Internal function to invoke `onERC721Received` on a target address
  259. * The call is not executed if the target address is not a contract
  260. * @param _from address representing the previous owner of the given token ID
  261. * @param _to target address that will receive the tokens
  262. * @param _tokenId uint256 ID of the token to be transferred
  263. * @param _data bytes optional data to send along with the call
  264. * @return whether the call correctly returned the expected magic value
  265. */
  266. function checkAndCallSafeTransfer(
  267. address _from,
  268. address _to,
  269. uint256 _tokenId,
  270. bytes _data
  271. )
  272. internal
  273. returns (bool)
  274. {
  275. if (!_to.isContract()) {
  276. return true;
  277. }
  278. bytes4 retval = ERC721Receiver(_to).onERC721Received(
  279. msg.sender, _from, _tokenId, _data);
  280. return (retval == ERC721_RECEIVED);
  281. }
  282. }