ERC721Basic.sol 11 KB

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