pragma solidity ^0.8.0;import "./IERC721.sol";import "./IERC721Receiver.sol";import "./IERC721Metadata.sol";import "./Address.sol";import "./Context.sol";import "./Strings.sol";import "./ERC165.sol";/** ERC721继承了Context, ERC165, IERC721, IERC721Metadata* 函数里的变量都是以(_)开头*/contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { // 把 Address 的方法给 address 使用 using Address for address; // 把 Strings 的方法给 uint256 使用 using Strings for uint256; // Token name // 私有属性 string private _name; // Token symbol // 私有属性 string private _symbol; // Mapping from token ID to owner address // 创建一个map, 名字是_owners, 映射关系是 uint256 => address mapping(uint256 => address) private _owners; // Mapping owner address to token count // 创建一个map, 名字是_balances, 映射关系是 address => uint256 mapping(address => uint256) private _balances; // Mapping from token ID to approved address // 创建一个map, 名字是_tokenApprovals, 映射关系是 uint256 => address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals // 创建一个map, 名字是_operatorApprovals, 映射关系是 address => bool mapping(address => mapping(address => bool)) private _operatorApprovals; /* * 构造函数,参数是name和symbol */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. * supportsInterface ERC165的方法, 通过interfaceId来判断合约是否实现某些方法 * 关键字`virtual`表示该函数可以在派生类中“overriding” */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. * 计算owner的nft数量 * 铸造nft时+1,传递给时+1 * 销毁nft时-1,送出时-1 */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. * 根据nft tokenID 查找这个nft属于谁 * 从前面创建的owner map 中查找 * 与balanceOf类似, 对nft所有权操作时会操作owner这个map */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev See {IERC721Metadata-name}. * 获得构造函数传入的名字 */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. * 获得构造函数传入的symbol */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. * 根据 tokenId 查看 tokenURI * 先判断tokenId是否存在 * 之后通过_baseURI()这个函数来拿到baseURI,查看_baseURI()这个函数,返回为“”??? * https://forum.openzeppelin.com/t/function-settokenuri-in-erc721-is-gone-with-pragma-0-8-0/5978 * 也就是说,_baseURI()需要我们自己进行扩充,维护一个map,把URI和tokenID对应起来 * 返回值是将baseURI和tokenId进行了编码打包为了一个字符串 * */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overriden in child contracts. * 默认为“”,需要我们自己进行扩充,维护一个map,把URI和tokenID对应起来 */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. * nft授权 * 不能给自己授权 * 调用方必须是nft的所有者 */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. * 获得某个tokenId的授权方 */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. * 给自己拥有的nft全部进行授权或取消授权 * true 授权, false 取消授权 * 通过_operatorApprovals map 来进行操作 * 最后调用ApprovalForAll事件 */ function setApprovalForAll(address operator, bool approved) public virtual override { require(operator != _msgSender(), "ERC721: approve to caller"); _operatorApprovals[_msgSender()][operator] = approved; emit ApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. * 查找_operatorApprovals map 判断 某个人是否有自己的全部授权 */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. * 流转nft * 调用_transfer()方法 */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. * 两个safeTransferFrom,最后data不一样,data相当于备注 */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. * _safeTransfer 第一步先调用_transfer * require要求to的地址如果是合约地址必须有payable,通过ERC165的supportsInterface来判断 */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory _data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). * 查找 _owners map 判断 tokenId 是否为 0 地址, 如果存在, 返回true, 如果不存在, 返回false * 实际意义是判断tokenId是否已经被分配、使用 * 在getApproved、_isApprovedOrOwner、_mint中有使用 */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. * 先判断tokenId是否已经存在 * 通过调用ownerOf查找这个nft的拥有者owner * 如果这个传入地址是拥有者或者已经被授权就返回true * 判断这个地址是否有权利操作这个nft * transferFrom、safeTransferFrom 有使用 * */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ERC721.ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. * 铸造nft * 调用_safeMint且_data为“” */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. * 铸造nft * 调用_mint,为啥没data了 * 要求了_checkOnERC721Received(address(0), to, tokenId, _data) */ function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. * 初始化nft * 空投地址不能为零地址 * tokenId必须为使用 * _beforeTokenTransfer可能需要自己实现 * 对应地址的nft数量加一,并且提添加到_owners这个map中 * 执行事件Transfer(address(0), to, tokenId),从零地址向to地址转tokenId * 但是只有tokenid,tokenid未和URI资源关联 * */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. * 销毁nft * 先查找nft的拥有者 * 将这个nft授权给零地址 (有点巧妙,为什么要进行授权,并不是真正的授权,而是此nft的授权者清空) * 拥有者的nft数量-1, owner map 也进行相应的删除 * 将这个nft从拥有者转给零地址,每个未铸造的nft是属于零地址的, 销毁后仍然还到零地址 */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. * 要转出的人必须是nft的拥有者, 授权者也不可以 * 转入地址不可以是零地址, 只有销毁才可以是零地址 * 要把当前nft的授权者清空 * 转出方的nft数量-1, 转入方的nft数量+1 * owners 的 map 也进行操作,替换为转入方 * 执行Transfer事件 */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits a {Approval} event. * 授权 * 对_tokenApprovals map进行操作, 把授权加上 * 这是否意味着每个nft只能有一个授权呢, 授权所有也可以, 为什么设计只有一个授权呢 * 执行授权事件 * 根据前面的一些方法, 如果to的地址是零地址, 代表取消授权 * 如果授权只能有一个, 那么授权给零地址自然为取消授权 */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value * 这个方法检验是否为ERC721Received * */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. * 在转账nft之谦执行的方法,自己扩充 */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {}}