跳到主要内容

ERC721 NFT标准

在区块链和加密货币的世界中,ERC721 标准为非同质化代币(Non-Fungible Token, NFT)的发展提供了重要基础。与普通的可互换代币(如 ERC20 代币)不同,每一枚 ERC721 代币都是独一无二的,这使它们成为艺术品、收藏品以及其他独特数字资产的理想载体。理解这一标准,对于开发和发布自己的 NFT 项目来说至关重要。

在本章,我们将详细探讨 ERC721 标准的机制,并通过一个具体的实例来演示如何实现基本的 ERC721 代币合约。

什么是 ERC721

ERC721 是一个 Ethereum 智能合约开发的一个标准接口,用于创建、跟踪和转移 NFT。该标准允许每个代币拥有唯一的属性和元数据。

CryptoKitties 是最早的主流区块链游戏之一,每一只加密猫都是一个独特的 NFT,拥有不同的外观、属性和稀有度。它通过 ERC721 标准进行代币化。玩家可以买卖、繁殖和收集这些虚拟的猫.

ERC721 与 ERC20 的比较

对比最广为人知的 ERC20 代币标准,ERC20 代币是可互换的,意味着每个代币都是相同的,并且具有相同的价值。相反,ERC721 的每一个代币都是独特的,并可以拥有不同的价值。

ERC721 的关键特征:

  1. 非同质化:每个代币都有独特的属性
  2. 所有权追踪:智能合约能准确记录每个代币的所有者
  3. 元数据可选性:合约可以包含一个可选的 URL,指向代币的元数据,如图片、文本等

ERC721 核心方法和事件

在 ERC721 标准中,定义了一系列方法和事件,这些都是为了保证非同质化代币的独特性、可跟踪性和可交易性。以下是一些关键的方法和事件:

方法

  • balanceOf(address _owner)

    • 描述:返回指定地址所拥有的代币数量
    • 参数:_owner:代币拥有者的地址
    • 返回值:该地址拥有的代币数量
  • ownerOf(uint256 _tokenId)

    • 描述:查询某个代币的所有者
    • 参数:_tokenId:代币的唯一识别 ID
    • 返回值:拥有此代币的地址
  • safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data)

    • 描述:安全地将代币从一个地址转移到另一个地址,调用时会检查接收者地址是否具备处理 ERC721 代币的能力
    • 参数:
      • _from:当前代币的拥有者地址
      • _to:代币将要被转移至的目标地址
      • _tokenId:将要被转移的代币的 ID
      • data:额外的数据,可能会在调用中使用
  • transferFrom(address _from, address _to, uint256 _tokenId)

    • 描述:将代币从一个地址转移到另一个地址,不检查接收者地址是否能处理 ERC721 代币
    • 参数:
      • _from:当前代币的拥有者地址
      • _to:代币将要被转移至的目标地址
      • _tokenId:将要被转移的代币的 ID
  • approve(address _approved, uint256 _tokenId)

    • 描述:授权某个地址管理特定的ERC721代币
    • 参数:
      • _approved:被授权的地址
      • _tokenId:代币的唯一识别 ID
  • getApproved(uint256 _tokenId)

    • 描述:获取被授权管理特定代币的地址
    • 参数:_tokenId:代币的唯一识别 ID
    • 返回值:被授权的管理该代币的地址
  • setApprovalForAll(address _operator, bool _approved)

    • 描述:将一个操作者地址设置为被批准或取消批准管理所有代币的权利
    • 参数:
      • _operator:操作者的地址
      • _approved:批准或取消批准的标志
  • isApprovedForAll(address _owner, address _operator)

    • 描述:查询一个操作者是否被批准管理某个所有者的所有代币
    • 参数:
      • _owner:代币拥有者的地址
      • _operator:操作者的地址
    • 返回值:是否被授权的布尔值

ERC721Metadata 是 ERC721 标准的一个非常重要的扩展,它为 NFT 增加了“名字(name)”、“符号(symbol)”和“元数据(tokenURI)”三个方法。这些方法引入了关于 NFT 的额外信息,这在市场上展示和交易NFT 时特别有用。

事件

  • Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId) 在代币被转移时触发

  • Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId) 在一个地址被授权管理另一个地址的特定代币时触发

  • ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved) 当一个操作者被授权或取消授权管理某个所有者的所有代币时触发

这些方法和事件构成了 ERC721 代币标准的核心,确保了代币的可追踪和独一无二的特性,以及安全的交易方式。

完整的技术标准详见 eip-721

ERC721 实现

我们将使用 OpenZeppelin 的库来实现一个基础的 ERC721 代币:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyNFT is ERC721URIStorage, Ownable {
uint256 private _tokenIdCounter = 0;

constructor() ERC721("MyNFT", "MNFT") {}

function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _tokenIdCounter;
_tokenIdCounter++;
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
}

在这个简单的示例中,MyNFT 合约继承了 ERC721URIStorage(继承了 ERC721) 和 Ownable 合约。

MyNFT 合约的构造函数设置了 NFT 的名称和符号。合约使用一个私有变量 _tokenIdCounter 来追踪发行的每个 NFT 的唯一编号。

safeMint 函数提供了方法来铸造新的 NFT。它接收一个地址和一个 URI 作为参数,铸造一个新的 NFT。内部调用了 OpenZeppelin 的 ERC721 合约提供的 _safeMint 函数 ,不仅创建一个新的 token,并将其分配给一个指定的地址,而且它还确保目标地址是可以接收 ERC721 token 的。通过 ERC721URIStorage 合约提供的 _setTokenURI 方法设置其 metadata URI。Ownable 合约的 onlyOwner 修饰器限制了只有合约的拥有者才可以调用 safeMint 函数。

总结

通过这一章,你应该对 ERC721 代币有了一个全面的了解,从它的基本原理到如何实现一个简单的代币合约。NFT 不仅仅可以代表艺术品和收藏品,随着技术的发展,其应用将变得更加广泛。