ERC721BasicToken.sol 12 KB

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