ERC721Basic.sol 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. pragma solidity ^0.4.24;
  2. import "./IERC721Basic.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 ERC721Basic is ERC165, IERC721Basic {
  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. * @param tokenId uint256 ID of the token to query the approval of
  81. * @return address currently approved for the given token ID
  82. */
  83. function getApproved(uint256 tokenId) public view returns (address) {
  84. require(_exists(tokenId));
  85. return _tokenApprovals[tokenId];
  86. }
  87. /**
  88. * @dev Sets or unsets the approval of a given operator
  89. * An operator is allowed to transfer all tokens of the sender on their behalf
  90. * @param to operator address to set the approval
  91. * @param approved representing the status of the approval to be set
  92. */
  93. function setApprovalForAll(address to, bool approved) public {
  94. require(to != msg.sender);
  95. _operatorApprovals[msg.sender][to] = approved;
  96. emit ApprovalForAll(msg.sender, to, approved);
  97. }
  98. /**
  99. * @dev Tells whether an operator is approved by a given owner
  100. * @param owner owner address which you want to query the approval of
  101. * @param operator operator address which you want to query the approval of
  102. * @return bool whether the given operator is approved by the given owner
  103. */
  104. function isApprovedForAll(
  105. address owner,
  106. address operator
  107. )
  108. public
  109. view
  110. returns (bool)
  111. {
  112. return _operatorApprovals[owner][operator];
  113. }
  114. /**
  115. * @dev Transfers the ownership of a given token ID to another address
  116. * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
  117. * Requires the msg sender to be the owner, approved, or operator
  118. * @param from current owner of the token
  119. * @param to address to receive the ownership of the given token ID
  120. * @param tokenId uint256 ID of the token to be transferred
  121. */
  122. function transferFrom(
  123. address from,
  124. address to,
  125. uint256 tokenId
  126. )
  127. public
  128. {
  129. require(_isApprovedOrOwner(msg.sender, tokenId));
  130. require(to != address(0));
  131. _clearApproval(from, tokenId);
  132. _removeTokenFrom(from, tokenId);
  133. _addTokenTo(to, tokenId);
  134. emit Transfer(from, to, tokenId);
  135. }
  136. /**
  137. * @dev Safely transfers the ownership of a given token ID to another address
  138. * If the target address is a contract, it must implement `onERC721Received`,
  139. * which is called upon a safe transfer, and return the magic value
  140. * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
  141. * the transfer is reverted.
  142. *
  143. * Requires the msg sender to be the owner, approved, or operator
  144. * @param from current owner of the token
  145. * @param to address to receive the ownership of the given token ID
  146. * @param tokenId uint256 ID of the token to be transferred
  147. */
  148. function safeTransferFrom(
  149. address from,
  150. address to,
  151. uint256 tokenId
  152. )
  153. public
  154. {
  155. // solium-disable-next-line arg-overflow
  156. safeTransferFrom(from, to, tokenId, "");
  157. }
  158. /**
  159. * @dev Safely transfers the ownership of a given token ID to another address
  160. * If the target address is a contract, it must implement `onERC721Received`,
  161. * which is called upon a safe transfer, and return the magic value
  162. * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
  163. * the transfer is reverted.
  164. * Requires the msg sender to be the owner, approved, or operator
  165. * @param from current owner of the token
  166. * @param to address to receive the ownership of the given token ID
  167. * @param tokenId uint256 ID of the token to be transferred
  168. * @param data bytes data to send along with a safe transfer check
  169. */
  170. function safeTransferFrom(
  171. address from,
  172. address to,
  173. uint256 tokenId,
  174. bytes data
  175. )
  176. public
  177. {
  178. transferFrom(from, to, tokenId);
  179. // solium-disable-next-line arg-overflow
  180. require(_checkAndCallSafeTransfer(from, to, tokenId, data));
  181. }
  182. /**
  183. * @dev Returns whether the specified token exists
  184. * @param tokenId uint256 ID of the token to query the existence of
  185. * @return whether the token exists
  186. */
  187. function _exists(uint256 tokenId) internal view returns (bool) {
  188. address owner = _tokenOwner[tokenId];
  189. return owner != address(0);
  190. }
  191. /**
  192. * @dev Returns whether the given spender can transfer a given token ID
  193. * @param spender address of the spender to query
  194. * @param tokenId uint256 ID of the token to be transferred
  195. * @return bool whether the msg.sender is approved for the given token ID,
  196. * is an operator of the owner, or is the owner of the token
  197. */
  198. function _isApprovedOrOwner(
  199. address spender,
  200. uint256 tokenId
  201. )
  202. internal
  203. view
  204. returns (bool)
  205. {
  206. address owner = ownerOf(tokenId);
  207. // Disable solium check because of
  208. // https://github.com/duaraghav8/Solium/issues/175
  209. // solium-disable-next-line operator-whitespace
  210. return (
  211. spender == owner ||
  212. getApproved(tokenId) == spender ||
  213. isApprovedForAll(owner, spender)
  214. );
  215. }
  216. /**
  217. * @dev Internal function to mint a new token
  218. * Reverts if the given token ID already exists
  219. * @param to The address that will own the minted token
  220. * @param tokenId uint256 ID of the token to be minted by the msg.sender
  221. */
  222. function _mint(address to, uint256 tokenId) internal {
  223. require(to != address(0));
  224. _addTokenTo(to, tokenId);
  225. emit Transfer(address(0), to, tokenId);
  226. }
  227. /**
  228. * @dev Internal function to burn a specific token
  229. * Reverts if the token does not exist
  230. * @param tokenId uint256 ID of the token being burned by the msg.sender
  231. */
  232. function _burn(address owner, uint256 tokenId) internal {
  233. _clearApproval(owner, tokenId);
  234. _removeTokenFrom(owner, tokenId);
  235. emit Transfer(owner, address(0), tokenId);
  236. }
  237. /**
  238. * @dev Internal function to clear current approval of a given token ID
  239. * Reverts if the given address is not indeed the owner of the token
  240. * @param owner owner of the token
  241. * @param tokenId uint256 ID of the token to be transferred
  242. */
  243. function _clearApproval(address owner, uint256 tokenId) internal {
  244. require(ownerOf(tokenId) == owner);
  245. if (_tokenApprovals[tokenId] != address(0)) {
  246. _tokenApprovals[tokenId] = address(0);
  247. }
  248. }
  249. /**
  250. * @dev Internal function to add a token ID to the list of a given address
  251. * @param to address representing the new owner of the given token ID
  252. * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
  253. */
  254. function _addTokenTo(address to, uint256 tokenId) internal {
  255. require(_tokenOwner[tokenId] == address(0));
  256. _tokenOwner[tokenId] = to;
  257. _ownedTokensCount[to] = _ownedTokensCount[to].add(1);
  258. }
  259. /**
  260. * @dev Internal function to remove a token ID from the list of a given address
  261. * @param from address representing the previous owner of the given token ID
  262. * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
  263. */
  264. function _removeTokenFrom(address from, uint256 tokenId) internal {
  265. require(ownerOf(tokenId) == from);
  266. _ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
  267. _tokenOwner[tokenId] = address(0);
  268. }
  269. /**
  270. * @dev Internal function to invoke `onERC721Received` on a target address
  271. * The call is not executed if the target address is not a contract
  272. * @param from address representing the previous owner of the given token ID
  273. * @param to target address that will receive the tokens
  274. * @param tokenId uint256 ID of the token to be transferred
  275. * @param data bytes optional data to send along with the call
  276. * @return whether the call correctly returned the expected magic value
  277. */
  278. function _checkAndCallSafeTransfer(
  279. address from,
  280. address to,
  281. uint256 tokenId,
  282. bytes data
  283. )
  284. internal
  285. returns (bool)
  286. {
  287. if (!to.isContract()) {
  288. return true;
  289. }
  290. bytes4 retval = IERC721Receiver(to).onERC721Received(
  291. msg.sender, from, tokenId, data);
  292. return (retval == _ERC721_RECEIVED);
  293. }
  294. }