ERC721.sol 11 KB

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