TON NFT 处理
概述
在本文档部分中,我们将向读者提供对 NFT 的更深刻理解。这将教导读者如何与 NFT 交互,并如何通过在 TON 区块链上发送的交易接收 NFT。
下面提供的信息假定读者已经深入了解了我们之前的有关 Toncoin 支付处理的部分,同时也假设他们具备通过编程与钱包智能合约交互的基本知识。
理解 NFT 的基础
在 TON 区块链上运行的 NFT 由 TEP-62 和 TEP-64 标准表示。
Open Network (TON) 区块链设计考虑了高性能,并包括了一个功能,该功能基于 TON 上的合约地址使用自动分片(用于帮助配置特定 NFT 设计)。为了实现最佳性能,单个 NFT 必须使用自己的智能合约。这使得可以创建任意大小(数量大或小)的 NFT 集合,同时也降低了开发成本和性能问题。然而,这种方法也为 NFT 集合的开发引入了新的考虑因素。
因为每个 NFT 都使用自己的智能合约,所以使用单个合约无法获取 NFT 集合中每个个体化 NFT 的信息。为了检索整个集合以及集合中每个 NFT 的信息,需要分别查询集合合约和每个个体 NFT 合约。出于同样的原因,要跟踪 NFT 转移,需要跟踪特定集合中每 个个体化 NFT 的所有交易。
NFT 集合
NFT 集合是一个用于索引和存储 NFT 内容的合约,并应包含以下接口:
获取方法 get_collection_data
(int next_item_index, cell collection_content, slice owner_address) get_collection_data()
获取关于集合的一般信息,表示如下:
next_item_index
- 如果集合是有序的,此分类指示集合中 NFT 的总数,以及用于铸造的下一个索引。对于无序的集合,next_item_index
的值是 -1,意味着集合 使用独特机制来跟踪 NFT(例如,TON DNS 域的哈希)。collection_content
- 一个以 TEP-64 兼容格式表示集合内容的 cell。owner_address
- 包含集合所有者地址的 slice(此值也可以为空)。
获取方法 get_nft_address_by_index
(slice nft_address) get_nft_address_by_index(int index)
此方法可用于验证 NFT 的真实性,并确认它是否确实属于特定集合。它还使用户能够通过提供其在集合中的索引来检索 NFT 地址。该方法应返回包含与提供的索引对应的 NFT 地址的 slice。
获取方法 get_nft_content
(cell full_content) get_nft_content(int index, cell individual_content)
由于集合充当 NFT 的公共数据存储,因此需要此方法来完善 NFT 内容。要使用此方法,首先需要通过调用相应的 get_nft_data()
方法获取 NFT 的 individual_content
。获取 individual_content
后,可以使用 NFT 索引和 individual_content
cell 调用 get_nft_content()
方法。该方法应返回一个包含 NFT 全部内容的 TEP-64 cell。
NFT 项
基本 NFT 应实现:
获取方法 get_nft_data()
(int init?, int index, slice collection_address, slice owner_address, cell individual_content) get_nft_data()
内联消息处理器 transfer
transfer#5fcc3d14 query_id:uint64 new_owner:MsgAddress response_destination:MsgAddress custom_payload:(Maybe ^Cell) forward_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) = InternalMsgBody
让我们看一下您需要在消息中填充的每个参数:
OP
-0x5fcc3d14
- 由 TEP-62 标准在转移消息中定义的常量。queryId
-uint64
- 用于跟踪消息的 uint64 数字。newOwnerAddress
-MsgAddress
- 用于将 NFT 转移至的合约地址。responseAddress
-MsgAddress
- 用于转移余额的地址。通常,额外的 TON 数量(例如,1 TON)被发送到 NFT 合约以确保它有足够的资金支付交易费用并创建新的转移(如果需要)。交易中的所有未使用资金都发送到responseAddress
。forwardAmount
-Coins
- 与转发消息一起使用的 TON 金额(通常设置为 0.01 TON)。由于 TON 使用异步架构,新所有者在成功接收交易后不会立即收到通知。为了通知新所有者,一个内部消息从 NFT 智能合约发送到newOwnerAddress
,使用forwardAmount
表示的值。转发消息将以ownership_assigned
OP(0x05138d91
)开始,紧随其后的是之前所有者的地址和forwardPayload
(如果存在)。forwardPayload
-Slice | Cell
- 作为ownership_assigned
通知消息的一部分发送。
如上所述,这个消息是与 NFT 交互的主要方式,用于在收到上述消息的通知后改变所有权。
例如,这种消息类型通常用于将 NFT Item 智能合约从 Wallet 智能合约发送。当 NFT 智能合约接收到此消息并执行它时,NFT 合约的存储(内部合约数据)将随着所有者 ID 的更新而更新。通过这种方式,NFT Item(合约)正确地更换所有者。此过程详细说明了标准 NFT 转移
在这种情况下,转发金额应设置为适当的值(对于常规钱包为 0.01 TON 或在您希望通过转移 NFT 来执行合约时更多),以确保新所有者接收到关于所有权转移的通知。除了以上述方式通知新所有者,如果不采取这一步骤,新所有者将不会知道他们已收到 NFT。
检索 NFT 数据
大多数 SDK 使用现成的处理器来检索 NFT 数据,包括:tonweb(js)、tonutils-go、pytonlib等。
要接收 NFT 数据,需要使用 get_nft_data()
检索机制。例如,我们必须验证以下 NFT 项地址 EQB43-VCmf17O7YMd51fAvOjcMkCw46N_3JMCoegH_ZDo40e
(也称为 foundation.ton 域)。
首先需要按照如下方式使用 toncenter.com API 执行 get 方法。:
curl -X 'POST' \
'https://toncenter.com/api/v2/runGetMethod' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"address": "EQB43-VCmf17O7YMd51fAvOjcMkCw46N_3JMCoegH_ZDo40e",
"method": "get_nft_data",
"stack": []
}'
响应通常类似于如下内容:
{
"ok": true,
"result": {
"@type": "smc.runResult",
"gas_used": 1581,
"stack": [
// init
[ "num", "-0x1" ],
// index
[ "num", "0x9c7d56cc115e7cf6c25e126bea77cbc3cb15d55106f2e397562591059963faa3" ],
// collection_address
[ "cell", { "bytes": "te6cckEBAQEAJAAAQ4AW7psr1kCofjDYDWbjVxFa4J78SsJhlfLDEm0U+hltmfDtDcL7" } ],
// owner_address
[ "cell", { "bytes": "te6cckEBAQEAJAAAQ4ATtS415xpeB1e+YRq/IsbVL8tFYPTNhzrjr5dcdgZdu5BlgvLe" } ],
// content
[ "cell", { "bytes": "te6cckEBCQEA7AABAwDAAQIBIAIDAUO/5NEvz/d9f/ZWh+aYYobkmY5/xar2cp73sULgTwvzeuvABAIBbgUGAER0c3/qevIyXwpbaQiTnJ1y+S20wMpSzKjOLEi7Jwi/GIVBAUG/I1EBQhz26hlqnwXCrTM5k2Qg5o03P1s9x0U4CBUQ7G4HAUG/LrgQbAsQe0P2KTvsDm8eA3Wr0ofDEIPQlYa5wXdpD/oIAEmf04AQe/qqXMblNo5fl5kYi9eYzSLgSrFtHY6k/DdIB0HmNQAQAEatAVFmGM9svpAE9og+dCyaLjylPtAuPjb0zvYqmO4eRJF0AIDBvlU=" } ]
],
"exit_code": 0,
"@extra": "1679535187.3836682:8:0.06118075068995321"
}
}
返回参数:
init
-boolean
- -1 表示 NFT 已初始化并可使用index
-uint256
- 集合中 NFT 的索引。可以是顺序的或以其他方式派生。例如,这可以表示使用 TON DNS 合约的 NFT 域哈希,而集合应该只在给定索引内拥有唯一的 NFT。collection_address
-Cell
- 包含 NFT 集合地址的 cell(可以为空)。owner_address
-Cell
- 包含当前所有者 NFT 地址的 cell(可以为空)。content
-Cell
- 包含 NFT 项内容的 cell(如果需要解析,需要参考 TEP-64 标准)。
检索集合内的所有 NFT
检索集合内所有 NFT 的过程取决于集合是否有序。我们在下面概述了两种过程。
有序集合
检索有序集合中的所有 NFT 相对简单,因为已经知道了检索所需的 NFT 数量,且可以轻松获取它们的地址。为了完成这一过程,应按顺序执行以下步骤:
- 使用 TonCenter API 调用集合合约中的
get_collection_data
方法,并从响应中检索next_item_index
值。 - 使用
get_nft_address_by_index
方法,传入索引值i
(最初设置为 0),以检索集合中第一个 NFT 的地址。 - 使用上一步获得的地址检索 NFT 项数据。接下来,验证初始 NFT Collection 智能合约是否与 NFT 项本身报告的 NFT Collection 智能合约一致(以确保集合没有挪用其他用户的 NFT 智能合约)。
- 使用来自上一步的
i
和individual_content
调用get_nft_content
方法。 i
增加 1 并重复步骤 2-5,直到i
等于next_item_index
。- 此时,您将拥有来自集合及其各个项目所需的信息。
无序集合
检索无序集合中的 NFT 列表更为困难,因为没有固有的方式来获取属于集合的 NFT 的地址。因此,需要解析集合合约中的所有交易并检查所有发出的消息以识别属于集合的 NFT 对应的消息。
为此,必须检索 NFT 数据,并在集合中使用 NFT 返回的 ID 调用 get_nft_address_by_index
方法。如果 NFT 合约地址与 get_nft_address_by_index
方法返回的地址匹配,这表明该 NFT 属于当前集合。但是,解析集合到所有消 息可能是一个漫长的过程,并且可能需要归档节点。
在 TON 之外的 NFT 处理
发送 NFT
要转移 NFT 所有权,需要从 NFT 所有者的钱包向 NFT 合约发送一条包含转移消息的 cell。这可以通过使用特定语言的库(例如 tonweb(js)、ton(js)、tonutils-go(go))来完成。
一旦创建了转移消息,就必须从所有者的钱包合约地址发送到 NFT 项合约地址,并附带足够的 TON 以支付关联的交易费用。
要将 NFT 从另一个用户转移到您自己,需要使用 TON Connect 2.0 或包含 ton:// 链接的简单二维码。例如:
ton://transfer/{nft_address}?amount={message_value}&bin={base_64_url(transfer_message)}
接收 NFTs
跟踪发送到某个智能合约地址(即用户的钱包)的 NFT 的过程类似于跟踪支付的机制。这是通过监听钱包中的所有新交易并解析它们来完成的。
下一步可能会根据具体情况而有所不同。让我们下面看几个不同的场景。
等待已知 NFT 地址转移的服务:
- 验证从 NFT 项目智能合约地址发送的新交易。
- 读取消息体的前 32 位作为使用
uint
类型,并验证它是否等于op::ownership_assigned()
(0x05138d91
) - 从消息体中读取接下来的 64 位作为
query_id
。 - 将消息体中的地址读作
prev_owner_address
。 - 现在可以管理您的新 NFT 了。
监听所有类型的 NFT 转移的服务:
- 检查所有新交易,忽略那些消息体长度小于 363 位(OP - 32,QueryID - 64,地址 - 267)的交易。
- 重复上面列表中详细介绍的步骤。
- 如果流程工作正常,则需要通过解析 NFT 及其所属的集合来验证 NFT 的真实性。接下来,需要确保 NFT 属于指定的集合。有关此过程的更多信息可以在
获取所有集合 NFTs
部分找到。可以通过使用 NFT 或集合的白名单来简化此过程。 - 现在可以管理您的新 NFT 了。