ERC721BasicToken.sol 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. pragma solidity ^0.4.23;
  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. * @dev The zero address indicates there is no approved address.
  97. * @dev There can only be one approved address per token at a given time.
  98. * @dev 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. * @dev 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. * @dev Usage of this method is discouraged, use `safeTransferFrom` whenever possible
  147. * @dev 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. * @dev 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. * @dev Requires the msg sender to be the owner, approved, or operator
  174. * @param _from current owner of the token
  175. * @param _to address to receive the ownership of the given token ID
  176. * @param _tokenId uint256 ID of the token to be transferred
  177. */
  178. function safeTransferFrom(
  179. address _from,
  180. address _to,
  181. uint256 _tokenId
  182. )
  183. public
  184. canTransfer(_tokenId)
  185. {
  186. // solium-disable-next-line arg-overflow
  187. safeTransferFrom(_from, _to, _tokenId, "");
  188. }
  189. /**
  190. * @dev Safely transfers the ownership of a given token ID to another address
  191. * @dev If the target address is a contract, it must implement `onERC721Received`,
  192. * which is called upon a safe transfer, and return the magic value
  193. * `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; otherwise,
  194. * the transfer is reverted.
  195. * @dev Requires the msg sender to be the owner, approved, or operator
  196. * @param _from current owner of the token
  197. * @param _to address to receive the ownership of the given token ID
  198. * @param _tokenId uint256 ID of the token to be transferred
  199. * @param _data bytes data to send along with a safe transfer check
  200. */
  201. function safeTransferFrom(
  202. address _from,
  203. address _to,
  204. uint256 _tokenId,
  205. bytes _data
  206. )
  207. public
  208. canTransfer(_tokenId)
  209. {
  210. transferFrom(_from, _to, _tokenId);
  211. // solium-disable-next-line arg-overflow
  212. require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
  213. }
  214. /**
  215. * @dev Returns whether the given spender can transfer a given token ID
  216. * @param _spender address of the spender to query
  217. * @param _tokenId uint256 ID of the token to be transferred
  218. * @return bool whether the msg.sender is approved for the given token ID,
  219. * is an operator of the owner, or is the owner of the token
  220. */
  221. function isApprovedOrOwner(
  222. address _spender,
  223. uint256 _tokenId
  224. )
  225. internal
  226. view
  227. returns (bool)
  228. {
  229. address owner = ownerOf(_tokenId);
  230. // Disable solium check because of
  231. // https://github.com/duaraghav8/Solium/issues/175
  232. // solium-disable-next-line operator-whitespace
  233. return (
  234. _spender == owner ||
  235. getApproved(_tokenId) == _spender ||
  236. isApprovedForAll(owner, _spender)
  237. );
  238. }
  239. /**
  240. * @dev Internal function to mint a new token
  241. * @dev Reverts if the given token ID already exists
  242. * @param _to The address that will own the minted token
  243. * @param _tokenId uint256 ID of the token to be minted by the msg.sender
  244. */
  245. function _mint(address _to, uint256 _tokenId) internal {
  246. require(_to != address(0));
  247. addTokenTo(_to, _tokenId);
  248. emit Transfer(address(0), _to, _tokenId);
  249. }
  250. /**
  251. * @dev Internal function to burn a specific token
  252. * @dev Reverts if the token does not exist
  253. * @param _tokenId uint256 ID of the token being burned by the msg.sender
  254. */
  255. function _burn(address _owner, uint256 _tokenId) internal {
  256. clearApproval(_owner, _tokenId);
  257. removeTokenFrom(_owner, _tokenId);
  258. emit Transfer(_owner, address(0), _tokenId);
  259. }
  260. /**
  261. * @dev Internal function to clear current approval of a given token ID
  262. * @dev Reverts if the given address is not indeed the owner of the token
  263. * @param _owner owner of the token
  264. * @param _tokenId uint256 ID of the token to be transferred
  265. */
  266. function clearApproval(address _owner, uint256 _tokenId) internal {
  267. require(ownerOf(_tokenId) == _owner);
  268. if (tokenApprovals[_tokenId] != address(0)) {
  269. tokenApprovals[_tokenId] = address(0);
  270. emit Approval(_owner, address(0), _tokenId);
  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. * @dev 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. }