1. pragma solidity ^0.8.0;
    2. import "./IERC721.sol";
    3. import "./IERC721Receiver.sol";
    4. import "./IERC721Metadata.sol";
    5. import "./Address.sol";
    6. import "./Context.sol";
    7. import "./Strings.sol";
    8. import "./ERC165.sol";
    9. /*
    10. * ERC721继承了Context, ERC165, IERC721, IERC721Metadata
    11. * 函数里的变量都是以(_)开头
    12. */
    13. contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    14. // 把 Address 的方法给 address 使用
    15. using Address for address;
    16. // 把 Strings 的方法给 uint256 使用
    17. using Strings for uint256;
    18. // Token name
    19. // 私有属性
    20. string private _name;
    21. // Token symbol
    22. // 私有属性
    23. string private _symbol;
    24. // Mapping from token ID to owner address
    25. // 创建一个map, 名字是_owners, 映射关系是 uint256 => address
    26. mapping(uint256 => address) private _owners;
    27. // Mapping owner address to token count
    28. // 创建一个map, 名字是_balances, 映射关系是 address => uint256
    29. mapping(address => uint256) private _balances;
    30. // Mapping from token ID to approved address
    31. // 创建一个map, 名字是_tokenApprovals, 映射关系是 uint256 => address
    32. mapping(uint256 => address) private _tokenApprovals;
    33. // Mapping from owner to operator approvals
    34. // 创建一个map, 名字是_operatorApprovals, 映射关系是 address => bool
    35. mapping(address => mapping(address => bool)) private _operatorApprovals;
    36. /*
    37. * 构造函数,参数是name和symbol
    38. */
    39. constructor(string memory name_, string memory symbol_) {
    40. _name = name_;
    41. _symbol = symbol_;
    42. }
    43. /**
    44. * @dev See {IERC165-supportsInterface}.
    45. * supportsInterface ERC165的方法, 通过interfaceId来判断合约是否实现某些方法
    46. * 关键字`virtual`表示该函数可以在派生类中“overriding”
    47. */
    48. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
    49. return
    50. interfaceId == type(IERC721).interfaceId ||
    51. interfaceId == type(IERC721Metadata).interfaceId ||
    52. super.supportsInterface(interfaceId);
    53. }
    54. /**
    55. * @dev See {IERC721-balanceOf}.
    56. * 计算owner的nft数量
    57. * 铸造nft时+1,传递给时+1
    58. * 销毁nft时-1,送出时-1
    59. */
    60. function balanceOf(address owner) public view virtual override returns (uint256) {
    61. require(owner != address(0), "ERC721: balance query for the zero address");
    62. return _balances[owner];
    63. }
    64. /**
    65. * @dev See {IERC721-ownerOf}.
    66. * 根据nft tokenID 查找这个nft属于谁
    67. * 从前面创建的owner map 中查找
    68. * 与balanceOf类似, 对nft所有权操作时会操作owner这个map
    69. */
    70. function ownerOf(uint256 tokenId) public view virtual override returns (address) {
    71. address owner = _owners[tokenId];
    72. require(owner != address(0), "ERC721: owner query for nonexistent token");
    73. return owner;
    74. }
    75. /**
    76. * @dev See {IERC721Metadata-name}.
    77. * 获得构造函数传入的名字
    78. */
    79. function name() public view virtual override returns (string memory) {
    80. return _name;
    81. }
    82. /**
    83. * @dev See {IERC721Metadata-symbol}.
    84. * 获得构造函数传入的symbol
    85. */
    86. function symbol() public view virtual override returns (string memory) {
    87. return _symbol;
    88. }
    89. /**
    90. * @dev See {IERC721Metadata-tokenURI}.
    91. * 根据 tokenId 查看 tokenURI
    92. * 先判断tokenId是否存在
    93. * 之后通过_baseURI()这个函数来拿到baseURI,查看_baseURI()这个函数,返回为“”???
    94. * https://forum.openzeppelin.com/t/function-settokenuri-in-erc721-is-gone-with-pragma-0-8-0/5978
    95. * 也就是说,_baseURI()需要我们自己进行扩充,维护一个map,把URI和tokenID对应起来
    96. * 返回值是将baseURI和tokenId进行了编码打包为了一个字符串
    97. *
    98. */
    99. function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
    100. require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
    101. string memory baseURI = _baseURI();
    102. return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    103. }
    104. /**
    105. * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
    106. * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
    107. * by default, can be overriden in child contracts.
    108. * 默认为“”,需要我们自己进行扩充,维护一个map,把URI和tokenID对应起来
    109. */
    110. function _baseURI() internal view virtual returns (string memory) {
    111. return "";
    112. }
    113. /**
    114. * @dev See {IERC721-approve}.
    115. * nft授权
    116. * 不能给自己授权
    117. * 调用方必须是nft的所有者
    118. */
    119. function approve(address to, uint256 tokenId) public virtual override {
    120. address owner = ERC721.ownerOf(tokenId);
    121. require(to != owner, "ERC721: approval to current owner");
    122. require(
    123. _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
    124. "ERC721: approve caller is not owner nor approved for all"
    125. );
    126. _approve(to, tokenId);
    127. }
    128. /**
    129. * @dev See {IERC721-getApproved}.
    130. * 获得某个tokenId的授权方
    131. */
    132. function getApproved(uint256 tokenId) public view virtual override returns (address) {
    133. require(_exists(tokenId), "ERC721: approved query for nonexistent token");
    134. return _tokenApprovals[tokenId];
    135. }
    136. /**
    137. * @dev See {IERC721-setApprovalForAll}.
    138. * 给自己拥有的nft全部进行授权或取消授权
    139. * true 授权, false 取消授权
    140. * 通过_operatorApprovals map 来进行操作
    141. * 最后调用ApprovalForAll事件
    142. */
    143. function setApprovalForAll(address operator, bool approved) public virtual override {
    144. require(operator != _msgSender(), "ERC721: approve to caller");
    145. _operatorApprovals[_msgSender()][operator] = approved;
    146. emit ApprovalForAll(_msgSender(), operator, approved);
    147. }
    148. /**
    149. * @dev See {IERC721-isApprovedForAll}.
    150. * 查找_operatorApprovals map 判断 某个人是否有自己的全部授权
    151. */
    152. function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
    153. return _operatorApprovals[owner][operator];
    154. }
    155. /**
    156. * @dev See {IERC721-transferFrom}.
    157. * 流转nft
    158. * 调用_transfer()方法
    159. */
    160. function transferFrom(
    161. address from,
    162. address to,
    163. uint256 tokenId
    164. ) public virtual override {
    165. //solhint-disable-next-line max-line-length
    166. require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
    167. _transfer(from, to, tokenId);
    168. }
    169. /**
    170. * @dev See {IERC721-safeTransferFrom}.
    171. * 两个safeTransferFrom,最后data不一样,data相当于备注
    172. */
    173. function safeTransferFrom(
    174. address from,
    175. address to,
    176. uint256 tokenId
    177. ) public virtual override {
    178. safeTransferFrom(from, to, tokenId, "");
    179. }
    180. /**
    181. * @dev See {IERC721-safeTransferFrom}.
    182. */
    183. function safeTransferFrom(
    184. address from,
    185. address to,
    186. uint256 tokenId,
    187. bytes memory _data
    188. ) public virtual override {
    189. require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
    190. _safeTransfer(from, to, tokenId, _data);
    191. }
    192. /**
    193. * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
    194. * are aware of the ERC721 protocol to prevent tokens from being forever locked.
    195. *
    196. * `_data` is additional data, it has no specified format and it is sent in call to `to`.
    197. *
    198. * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
    199. * implement alternative mechanisms to perform token transfer, such as signature-based.
    200. *
    201. * Requirements:
    202. *
    203. * - `from` cannot be the zero address.
    204. * - `to` cannot be the zero address.
    205. * - `tokenId` token must exist and be owned by `from`.
    206. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    207. *
    208. * Emits a {Transfer} event.
    209. * _safeTransfer 第一步先调用_transfer
    210. * require要求to的地址如果是合约地址必须有payable,通过ERC165的supportsInterface来判断
    211. */
    212. function _safeTransfer(
    213. address from,
    214. address to,
    215. uint256 tokenId,
    216. bytes memory _data
    217. ) internal virtual {
    218. _transfer(from, to, tokenId);
    219. require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    220. }
    221. /**
    222. * @dev Returns whether `tokenId` exists.
    223. *
    224. * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
    225. *
    226. * Tokens start existing when they are minted (`_mint`),
    227. * and stop existing when they are burned (`_burn`).
    228. * 查找 _owners map 判断 tokenId 是否为 0 地址, 如果存在, 返回true, 如果不存在, 返回false
    229. * 实际意义是判断tokenId是否已经被分配、使用
    230. * 在getApproved、_isApprovedOrOwner、_mint中有使用
    231. */
    232. function _exists(uint256 tokenId) internal view virtual returns (bool) {
    233. return _owners[tokenId] != address(0);
    234. }
    235. /**
    236. * @dev Returns whether `spender` is allowed to manage `tokenId`.
    237. *
    238. * Requirements:
    239. *
    240. * - `tokenId` must exist.
    241. * 先判断tokenId是否已经存在
    242. * 通过调用ownerOf查找这个nft的拥有者owner
    243. * 如果这个传入地址是拥有者或者已经被授权就返回true
    244. * 判断这个地址是否有权利操作这个nft
    245. * transferFrom、safeTransferFrom 有使用
    246. *
    247. */
    248. function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
    249. require(_exists(tokenId), "ERC721: operator query for nonexistent token");
    250. address owner = ERC721.ownerOf(tokenId);
    251. return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    252. }
    253. /**
    254. * @dev Safely mints `tokenId` and transfers it to `to`.
    255. *
    256. * Requirements:
    257. *
    258. * - `tokenId` must not exist.
    259. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    260. *
    261. * Emits a {Transfer} event.
    262. * 铸造nft
    263. * 调用_safeMint且_data为“”
    264. */
    265. function _safeMint(address to, uint256 tokenId) internal virtual {
    266. _safeMint(to, tokenId, "");
    267. }
    268. /**
    269. * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
    270. * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
    271. * 铸造nft
    272. * 调用_mint,为啥没data了
    273. * 要求了_checkOnERC721Received(address(0), to, tokenId, _data)
    274. */
    275. function _safeMint(
    276. address to,
    277. uint256 tokenId,
    278. bytes memory _data
    279. ) internal virtual {
    280. _mint(to, tokenId);
    281. require(
    282. _checkOnERC721Received(address(0), to, tokenId, _data),
    283. "ERC721: transfer to non ERC721Receiver implementer"
    284. );
    285. }
    286. /**
    287. * @dev Mints `tokenId` and transfers it to `to`.
    288. *
    289. * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
    290. *
    291. * Requirements:
    292. *
    293. * - `tokenId` must not exist.
    294. * - `to` cannot be the zero address.
    295. *
    296. * Emits a {Transfer} event.
    297. * 初始化nft
    298. * 空投地址不能为零地址
    299. * tokenId必须为使用
    300. * _beforeTokenTransfer可能需要自己实现
    301. * 对应地址的nft数量加一,并且提添加到_owners这个map中
    302. * 执行事件Transfer(address(0), to, tokenId),从零地址向to地址转tokenId
    303. * 但是只有tokenid,tokenid未和URI资源关联
    304. *
    305. */
    306. function _mint(address to, uint256 tokenId) internal virtual {
    307. require(to != address(0), "ERC721: mint to the zero address");
    308. require(!_exists(tokenId), "ERC721: token already minted");
    309. _beforeTokenTransfer(address(0), to, tokenId);
    310. _balances[to] += 1;
    311. _owners[tokenId] = to;
    312. emit Transfer(address(0), to, tokenId);
    313. }
    314. /**
    315. * @dev Destroys `tokenId`.
    316. * The approval is cleared when the token is burned.
    317. *
    318. * Requirements:
    319. *
    320. * - `tokenId` must exist.
    321. *
    322. * Emits a {Transfer} event.
    323. * 销毁nft
    324. * 先查找nft的拥有者
    325. * 将这个nft授权给零地址 (有点巧妙,为什么要进行授权,并不是真正的授权,而是此nft的授权者清空)
    326. * 拥有者的nft数量-1, owner map 也进行相应的删除
    327. * 将这个nft从拥有者转给零地址,每个未铸造的nft是属于零地址的, 销毁后仍然还到零地址
    328. */
    329. function _burn(uint256 tokenId) internal virtual {
    330. address owner = ERC721.ownerOf(tokenId);
    331. _beforeTokenTransfer(owner, address(0), tokenId);
    332. // Clear approvals
    333. _approve(address(0), tokenId);
    334. _balances[owner] -= 1;
    335. delete _owners[tokenId];
    336. emit Transfer(owner, address(0), tokenId);
    337. }
    338. /**
    339. * @dev Transfers `tokenId` from `from` to `to`.
    340. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
    341. *
    342. * Requirements:
    343. *
    344. * - `to` cannot be the zero address.
    345. * - `tokenId` token must be owned by `from`.
    346. *
    347. * Emits a {Transfer} event.
    348. * 要转出的人必须是nft的拥有者, 授权者也不可以
    349. * 转入地址不可以是零地址, 只有销毁才可以是零地址
    350. * 要把当前nft的授权者清空
    351. * 转出方的nft数量-1, 转入方的nft数量+1
    352. * owners 的 map 也进行操作,替换为转入方
    353. * 执行Transfer事件
    354. */
    355. function _transfer(
    356. address from,
    357. address to,
    358. uint256 tokenId
    359. ) internal virtual {
    360. require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
    361. require(to != address(0), "ERC721: transfer to the zero address");
    362. _beforeTokenTransfer(from, to, tokenId);
    363. // Clear approvals from the previous owner
    364. _approve(address(0), tokenId);
    365. _balances[from] -= 1;
    366. _balances[to] += 1;
    367. _owners[tokenId] = to;
    368. emit Transfer(from, to, tokenId);
    369. }
    370. /**
    371. * @dev Approve `to` to operate on `tokenId`
    372. *
    373. * Emits a {Approval} event.
    374. * 授权
    375. * 对_tokenApprovals map进行操作, 把授权加上
    376. * 这是否意味着每个nft只能有一个授权呢, 授权所有也可以, 为什么设计只有一个授权呢
    377. * 执行授权事件
    378. * 根据前面的一些方法, 如果to的地址是零地址, 代表取消授权
    379. * 如果授权只能有一个, 那么授权给零地址自然为取消授权
    380. */
    381. function _approve(address to, uint256 tokenId) internal virtual {
    382. _tokenApprovals[tokenId] = to;
    383. emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    384. }
    385. /**
    386. * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
    387. * The call is not executed if the target address is not a contract.
    388. *
    389. * @param from address representing the previous owner of the given token ID
    390. * @param to target address that will receive the tokens
    391. * @param tokenId uint256 ID of the token to be transferred
    392. * @param _data bytes optional data to send along with the call
    393. * @return bool whether the call correctly returned the expected magic value
    394. * 这个方法检验是否为ERC721Received
    395. *
    396. */
    397. function _checkOnERC721Received(
    398. address from,
    399. address to,
    400. uint256 tokenId,
    401. bytes memory _data
    402. ) private returns (bool) {
    403. if (to.isContract()) {
    404. try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
    405. return retval == IERC721Receiver.onERC721Received.selector;
    406. } catch (bytes memory reason) {
    407. if (reason.length == 0) {
    408. revert("ERC721: transfer to non ERC721Receiver implementer");
    409. } else {
    410. assembly {
    411. revert(add(32, reason), mload(reason))
    412. }
    413. }
    414. }
    415. } else {
    416. return true;
    417. }
    418. }
    419. /**
    420. * @dev Hook that is called before any token transfer. This includes minting
    421. * and burning.
    422. *
    423. * Calling conditions:
    424. *
    425. * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
    426. * transferred to `to`.
    427. * - When `from` is zero, `tokenId` will be minted for `to`.
    428. * - When `to` is zero, ``from``'s `tokenId` will be burned.
    429. * - `from` and `to` are never both zero.
    430. *
    431. * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
    432. * 在转账nft之谦执行的方法,自己扩充
    433. */
    434. function _beforeTokenTransfer(
    435. address from,
    436. address to,
    437. uint256 tokenId
    438. ) internal virtual {}
    439. }