ERC721BasicToken.sol 10 KB

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