变更记录
- 2021-05-01: 初始草案
- 2021-07-02: 评审更新
- 2022-06-15: 添加批量操作
- 2022-11-11: 移除对 classID 和 tokenID 的严格校验
状态
已提议摘要
本 ADR 定义了x/nft 模块,它是 NFT 的通用实现,与 ERC721 大致“兼容”。使用 x/nft 模块的应用必须实现以下函数:
MsgNewClass- 接收用户创建类的请求,并调用x/nft模块的NewClass。MsgUpdateClass- 接收用户更新类的请求,并调用x/nft模块的UpdateClass。MsgMintNFT- 接收用户铸造 nft 的请求,并调用x/nft模块的MintNFT。BurnNFT- 接收用户销毁 nft 的请求,并调用x/nft模块的BurnNFT。UpdateNFT- 接收用户更新 nft 的请求,并调用x/nft模块的UpdateNFT。
背景
NFT 并不只是加密艺术,这对于 Cosmos 生态系统积累价值非常有帮助。因此,Cosmos Hub 应当实现 NFT 功能,并启用统一机制来存储和发送 NFT 所有权的代表信息,详见链接。 如 #9065 中所讨论,可以考虑若干潜在方案:- irismod/nft 和 modules/incubator/nft
- CW721
- DID NFTs
- interNFT
决策
我们创建一个x/nft 模块,它包含以下功能:
- 存储 NFT 并跟踪其所有权。
- 暴露
Keeper接口,供组合模块转移、铸造和销毁 NFT。 - 暴露外部
Message接口,供用户转移其 NFT 的所有权。 - 查询 NFT 及其供应信息。
NFT 或 Class 类型的一部分。应用特定的 NFT 数据应编码在 NFT.data 中,以保证跨链完整性。与 NFT 相关但对完整性不重要的其他对象,可以属于应用专用模块。
类型
我们提出两种主要类型:Class— 描述 NFT 类。可以将其理解为智能合约地址。NFT— 表示唯一、不可替代资产的对象。每个 NFT 都关联一个 Class。
Class
NFT Class 可类比于一个 ERC-721 智能合约(提供智能合约的描述),在其之下可以创建和管理一组 NFT。id用作存储该类的主索引;必填name是 NFT 类的描述性名称;可选symbol是 NFT 类通常在交易所显示的符号;可选description是 NFT 类的详细描述;可选uri是链下存储的类元数据 URI。它应当是一个 JSON 文件,包含 NFT 类及 NFT 数据模式的元数据(OpenSea 示例);可选uri_hash是uri指向文档的哈希;可选data是该类的应用特定元数据;可选
NFT
我们将NFT 的通用模型定义如下。
-
class_id是 NFT 所属 NFT 类的标识符;必填 -
id是 NFT 的标识符,在其类的范围内唯一。它由 NFT 的创建者指定,未来可能扩展为使用 DID。class_id与id组合后可唯一标识一个 NFT,并用作存储该 NFT 的主索引;必填 -
uri是链下存储的 NFT 元数据 URI。应指向一个包含该 NFT 元数据的 JSON 文件(参考:ERC721 标准和 OpenSea 扩展);必填 -
uri_hash是uri指向文档的哈希;可选 -
data是 NFT 的应用特定数据。组合模块可以用它来指定 NFT 的附加属性;可选
data 可以采用哪些值;不过,最佳实践建议上层 NFT 模块应明确说明其内容。虽然该字段的值并不能提供管理 NFT 记录所需的额外上下文,这意味着从技术上讲该字段可以从规范中移除,但该字段的存在使基础的信息展示/UI 功能成为可能。
Keeper 接口
x/nft 并使用其 Keeper 的组合模块中。
Msg 服务
MsgSend 可用于将 NFT 的所有权转移到另一个地址。
服务端的实现概要如下:
x/nft 模块的查询服务方法如下:
互操作性
互操作性的核心是在模块之间和链之间复用资产。前者通过 ADR-33: Protobuf 客户端-服务端通信实现。写作本文时,ADR-33 尚未最终定稿。后者通过 IBC 实现。这里我们将重点关注 IBC 这一侧。 IBC 按模块实现。在这里,我们统一将 NFT 记录并管理在 x/nft 中。这要求创建一个新的 IBC 标准并实现它。 对于 IBC 互操作性,NFT 自定义模块必须使用 IBC 客户端能够理解的 NFT 对象类型。因此,为了实现 x/nft 互操作性,自定义 NFT 实现(例如:x/cryptokitty)应当使用规范的 x/nft 模块,并将所有 NFT 余额维护功能代理到 x/nft;否则就需要使用 IBC 客户端能够理解的 NFT 对象类型重新实现全部功能。换句话说:x/nft 将成为所有 Cosmos NFT 的标准 NFT 注册表(例如:x/cryptokitty 会在 x/nft 中注册一个 kitty NFT,并使用 x/nft 进行账务维护)。这一点已在将 x/bank 用作通用资产余额账本的背景下进行过讨论。如果不使用 x/nft,就需要为 IBC 再实现另一个模块。影响
向后兼容性
没有向后不兼容问题。向前兼容性
本规范在 NFT 标识符方面符合 ERC-721 智能合约规范。需要注意的是,ERC-721 基于(合约地址,uint256 tokenId)定义唯一性,而我们之所以能隐式遵循这一点,是因为当前的目标是由单个模块跟踪 NFT 标识符。注意:使用(可变的)data 字段来判定唯一性并不安全。正面影响
- Cosmos Hub 上可提供 NFT 标识符。
- 能够为 Cosmos Hub 构建不同的 NFT 模块,例如 ERC-721。
- 支持与 IBC 以及 Gravity Bridge 等其他跨链基础设施互操作的 NFT 模块
负面影响
- x/nft 需要新的 IBC 应用
- 需要 CW721 适配器
中性影响
- 其他功能需要更多模块。例如,NFT 交易功能需要托管模块,定义 NFT 属性需要收藏品模块。
进一步讨论
对于 Hub 上的其他类型应用,未来可以开发更多面向特定应用的模块:x/nft/custody:托管 NFT,以支持交易功能。x/nft/marketplace:使用 sdk.Coins 买卖 NFT。x/fractional:将某项资产(NFT 或其他资产)的所有权拆分给多个利益相关方的模块。x/group在大多数情况下应当可以满足需求。
参考资料
Changelog
- 2021-05-01: Initial Draft
- 2021-07-02: Review updates
- 2022-06-15: Add batch operation
- 2022-11-11: Remove strict validation of classID and tokenID
Status
PROPOSEDAbstract
This ADR defines thex/nft module which is a generic implementation of NFTs, roughly “compatible” with ERC721. Applications using the x/nft module must implement the following functions:
MsgNewClass- Receive the user’s request to create a class, and call theNewClassof thex/nftmodule.MsgUpdateClass- Receive the user’s request to update a class, and call theUpdateClassof thex/nftmodule.MsgMintNFT- Receive the user’s request to mint a nft, and call theMintNFTof thex/nftmodule.BurnNFT- Receive the user’s request to burn a nft, and call theBurnNFTof thex/nftmodule.UpdateNFT- Receive the user’s request to update a nft, and call theUpdateNFTof thex/nftmodule.
Context
NFTs are more than just crypto art, which is very helpful for accruing value to the Cosmos ecosystem. As a result, Cosmos Hub should implement NFT functions and enable a unified mechanism for storing and sending the ownership representative of NFTs as discussed in Link. As discussed in #9065, several potential solutions can be considered:- irismod/nft and modules/incubator/nft
- CW721
- DID NFTs
- interNFT
Decision
We create ax/nft module, which contains the following functionality:
- Store NFTs and track their ownership.
- Expose
Keeperinterface for composing modules to transfer, mint and burn NFTs. - Expose external
Messageinterface for users to transfer ownership of their NFTs. - Query NFTs and their supply information.
NFT or Class type described below. The app specific NFT data should be encoded in NFT.data for cross-chain integrity. Other objects related to NFT, which are not important for integrity can be part of the app specific module.
Types
We propose two main types:Class— describes NFT class. We can think about it as a smart contract address.NFT— object representing unique, non fungible asset. Each NFT is associated with a Class.
Class
NFT Class is comparable to an ERC-721 smart contract (provides description of a smart contract), under which a collection of NFTs can be created and managed.idis used as the primary index for storing the class; requirednameis a descriptive name of the NFT class; optionalsymbolis the symbol usually shown on exchanges for the NFT class; optionaldescriptionis a detailed description of the NFT class; optionaluriis a URI for the class metadata stored off chain. It should be a JSON file that contains metadata about the NFT class and NFT data schema (OpenSea example); optionaluri_hashis a hash of the document pointed by uri; optionaldatais app specific metadata of the class; optional
NFT
We define a general model forNFT as follows.
-
class_idis the identifier of the NFT class where the NFT belongs; required -
idis an identifier of the NFT, unique within the scope of its class. It is specified by the creator of the NFT and may be expanded to use DID in the future.class_idcombined withiduniquely identifies an NFT and is used as the primary index for storing the NFT; required -
uriis a URI for the NFT metadata stored off chain. Should point to a JSON file that contains metadata about this NFT (Ref: ERC721 standard and OpenSea extension); required -
uri_hashis a hash of the document pointed by uri; optional -
datais an app specific data of the NFT. CAN be used by composing modules to specify additional properties of the NFT; optional
data can take; however, best practices recommend upper-level NFT modules clearly specify their contents. Although the value of this field doesn’t provide the additional context required to manage NFT records, which means that the field can technically be removed from the specification, the field’s existence allows basic informational/UI functionality.
Keeper Interface
x/nft and use its Keeper.
Msg Service
MsgSend can be used to transfer the ownership of an NFT to another address.
The implementation outline of the server is as follows:
x/nft module are:
Interoperability
Interoperability is all about reusing assets between modules and chains. The former one is achieved by ADR-33: Protobuf client - server communication. At the time of writing ADR-33 is not finalized. The latter is achieved by IBC. Here we will focus on the IBC side. IBC is implemented per module. Here, we aligned that NFTs will be recorded and managed in the x/nft. This requires creation of a new IBC standard and implementation of it. For IBC interoperability, NFT custom modules MUST use the NFT object type understood by the IBC client. So, for x/nft interoperability, custom NFT implementations (example: x/cryptokitty) should use the canonical x/nft module and proxy all NFT balance keeping functionality to x/nft or else re-implement all functionality using the NFT object type understood by the IBC client. In other words: x/nft becomes the standard NFT registry for all Cosmos NFTs (example: x/cryptokitty will register a kitty NFT in x/nft and use x/nft for book keeping). This was discussed in the context of using x/bank as a general asset balance book. Not using x/nft will require implementing another module for IBC.Consequences
Backward Compatibility
No backward incompatibilities.Forward Compatibility
This specification conforms to the ERC-721 smart contract specification for NFT identifiers. Note that ERC-721 defines uniqueness based on (contract address, uint256 tokenId), and we conform to this implicitly because a single module is currently aimed to track NFT identifiers. Note: use of the (mutable) data field to determine uniqueness is not safe.sPositive
- NFT identifiers available on Cosmos Hub.
- Ability to build different NFT modules for the Cosmos Hub, e.g., ERC-721.
- NFT module which supports interoperability with IBC and other cross-chain infrastructures like Gravity Bridge
Negative
- New IBC app is required for x/nft
- CW721 adapter is required
Neutral
- Other functions need more modules. For example, a custody module is needed for NFT trading function, a collectible module is needed for defining NFT properties.
Further Discussions
For other kinds of applications on the Hub, more app-specific modules can be developed in the future:x/nft/custody: custody of NFTs to support trading functionality.x/nft/marketplace: selling and buying NFTs using sdk.Coins.x/fractional: a module to split an ownership of an asset (NFT or other assets) for multiple stakeholder.x/groupshould work for most of the cases.