代币标准--ERC721协议源码解析

  • Nolan
  • 更新于 2022-08-06 19:37
  • 阅读 3734

代币标准--ERC721协议源码解析

IERC165接口定义

interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

IERC721:ERC721的接口定义

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

IERC721继承IERC165接口

interface IERC721 is IERC165 {

Transfer事件

  // 定义Transfer事件,在发生交易转移时触发。Solidity event在 EVM 的日志记录功能之上提供了一个抽象。应用程序可以通过以太坊客户端的 RPC 接口订阅和监听这些事件
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

Approval事件

// 定义Approval事件,在发生代币授权时触发该事件
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

ApprovalForAll事件

// 记录owner全部token授权给 operate事件
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

balanceOf函数

// 记录
    function balanceOf(address owner) external view returns (uint256 balance);

ownerOf函数

// 获取token的拥有者地址
    function ownerOf(uint256 tokenId) external view returns (address owner);

safeTransferFrom函数

// 转移token从from到to地址
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

safeTransferFrom函数

// 转移token从from到to地址
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

transferFrom函数

// 转移token从from到to地址 被
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

approve函数

// 将token授权给to地址
    function approve(address to, uint256 tokenId) external;

setApprovalForAll函数

// 授权全部token给operate地址
    function setApprovalForAll(address operator, bool _approved) external;

getApproved函数

// 获取token的授权者地址
    function getApproved(uint256 tokenId) external view returns (address operator);

isApprovedForAll函数

// 判断owner是否授权给operator
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

ERC721

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

ERC721继承Context、ERC165、IERC721、IERC721Metadata

contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;
    // 代币名称
    string private _name;
    // 代币标志
    string private _symbol;
    // tokenId 和 拥有者地址的映射
    mapping(uint256 => address) private _owners;
    // 地址拥有的代币数量
    mapping(address => uint256) private _balances;
    // token 与 被授权的地址的映射
    mapping(uint256 => address) private _tokenApprovals;
    // 拥有者 和 操作者之间的授权映射
    mapping(address => mapping(address => bool)) private _operatorApprovals;
    // 构造函数 初始化 name_, symbol_
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

supportsInterface函数

    // 是否使用了 ERC721接口
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

balanceOf函数

    // 获取owner地址代币数量
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: address zero is not a valid owner");
        return _balances[owner];
    }

ownerOf函数

    // 获取代币拥有地址
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: invalid token ID");
        return owner;
    }

name函数

    // 获取代币名称
    function name() public view virtual override returns (string memory) {
        return _name;
    }

symbol函数

    // 获取代币标识
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

tokenURI函数

    //  获取tokenURI
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
    //  检查token是否存在
        _requireMinted(tokenId);
   //  获取baseURI
        string memory baseURI = _baseURI();

        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

_baseURI函数

// 获取baseURI
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

approve函数

    function approve(address to, uint256 tokenId) public virtual override {
        // 获取token的owner地址
        address owner = ERC721.ownerOf(tokenId);

        // 检查 to 和 owner 不相等
        require(to != owner, "ERC721: approval to current owner");

        // 检查 合约调用者是owner 或者 合约调用者获得了owner的授权approve
        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not token owner or approved for all"
        );
        // 授权
        _approve(to, tokenId);
    }

getApproved函数

    // 获取token的approve地址
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
    //  检查token是否存在
        _requireMinted(tokenId);
        return _tokenApprovals[tokenId];
    }

setApprovalForAll函数

    // 设置 给operator的授权情况
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

isApprovedForAll函数

    // 判断 owner是否授权给operate
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

transferFrom函数

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //检查 合约调用者是否是token的拥有者或者被授权approve
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
        // 转移token
        _transfer(from, to, tokenId);
    }

safeTransferFrom函数

    // 转移token
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

safeTransferFrom函数

    // 转移函数
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public virtual override {
    //检查 合约调用者是否是token的拥有者或者被授权approve
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
        _safeTransfer(from, to, tokenId, data);
    }

_safeTransfer函数

   // 转移token
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _transfer(from, to, tokenId);
        // 检查合约地址是否实现ERC721Receiver
        require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
    }

_exists 函数

// 判断token是否存在
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

_isApprovedOrOwner函数

    // 判断是否是token的拥有者或者被授权approve
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
    }

_safeMint函数

  // 铸造token
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

_safeMint函数

// 铸造token
    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"
        );
    }

_mint函数

// 铸造token
    function _mint(address to, uint256 tokenId) internal virtual {
    // 检查to不为空地址
        require(to != address(0), "ERC721: mint to the zero address");
   // 检查token是否存在
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);
  // to地址余额+1
        _balances[to] += 1;
  // 添加映射
        _owners[tokenId] = to;
// 触发 Transfer事件
        emit Transfer(address(0), to, tokenId);

        _afterTokenTransfer(address(0), to, tokenId);
    }

_burn函数

// 销毁token
    function _burn(uint256 tokenId) internal virtual {
        // 获取token 拥有者地址
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // 删除token与授权者映射
        delete _tokenApprovals[tokenId];
        // owner账户余额-1
        _balances[owner] -= 1;
        // 删除token 与拥有者映射
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);

        _afterTokenTransfer(owner, address(0), tokenId);
    }

_transfer函数

// 转移token
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
    // 检查token拥有者与 from地址是否一致
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
    // 检查 to地址是否为空地址
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        //  移除token授权
        delete _tokenApprovals[tokenId];
        // from地址token数量-1
        _balances[from] -= 1;
         // to地址token数量-1
        _balances[to] += 1;
        // 添加to与token的映射关系
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

_approve函数

// 将token授权给to
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

_setApprovalForAll函数

// 设置owner与operate的approve授权状态
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
    // 检查owner地址和operate地址是否一致
        require(owner != operator, "ERC721: approve to caller");
    // 设置owner与operate授权状态
        _operatorApprovals[owner][operator] = approved;
    // 触发ApprovalForAll时间 记录信息
        emit ApprovalForAll(owner, operator, approved);
    }

_requireMinted函数

    // 判断是否token是否已经存在
    function _requireMinted(uint256 tokenId) internal view virtual {
        require(_exists(tokenId), "ERC721: invalid token ID");
    }

_checkOnERC721Received 函数

// 检查地址,如果地址是账户,则返回true,是合约的话则会判断,该合约是否有引用IERC721Receiver这个接口
//作为EIP-721的要求,如果一个合约要接受EIP-721,其必须要实现onERC721Received方法,当用户调用safeTransferFrom时,会在转账结束时,调用to地址的onERC721Received方法,此时该方法的返回值应该为bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))
    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 {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

_beforeTokenTransfer 函数

// 定义转移代币前的函数
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}

_afterTokenTransfer 函数

// 定义转移代币后的函数
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

2 条评论

请先 登录 后评论
Nolan
Nolan
江湖只有他的大名,没有他的介绍。