跳转到内容

非同质化代币 (NFT)

此页列出了与 [NFTs]交互的常见例子(https://docs.ton.org/develop/dapps/asset-processing/nfts)。

接受 NFT 所有权分配

指派的 NFT 所有权的通知信息具有以下结构:

message(0x05138d91) NFTOwnershipAssigned {
previousOwner: Address;
forwardPayload: Slice as remaining;
}

使用 receiver 函数来接受通知消息。

验证可以通过两种方式进行:

  1. 直接保存 NFT 项目地址并进行验证。
import "@stdlib/deploy";
message(0x05138d91) NFTOwnershipAssigned {
previousOwner: Address;
forwardPayload: Slice as remaining;
}
contract SingleNft with Deployable {
nftItemAddress: Address;
init(nftItemAddress: Address) {
self.nftItemAddress = nftItemAddress;
}
receive(msg: NFTOwnershipAssigned) {
require(self.nftItemAddress == sender(), "NFT contract is not the sender");
// your logic of processing nft ownership assign notification
}
}
  1. 使用 StateInit 和派生的 NFT 项目地址。
import "@stdlib/deploy";
message(0x05138d91) NFTOwnershipAssigned {
previousOwner: Address;
forwardPayload: Slice as remaining;
}
struct NFTItemInitData {
index: Int as uint64;
collectionAddress: Address;
}
inline fun calculateNFTAddress(index: Int, collectionAddress: Address, nftCode: Cell): Address {
let initData = NFTItemInitData{
index,
collectionAddress,
};
return contractAddress(StateInit{code: nftCode, data: initData.toCell()});
}
contract NftInCollection with Deployable {
nftCollectionAddress: Address;
nftItemIndex: Int as uint64;
nftCode: Cell;
init(nftCollectionAddress: Address, nftItemIndex: Int, nftCode: Cell) {
self.nftCollectionAddress = nftCollectionAddress;
self.nftItemIndex = nftItemIndex;
self.nftCode = nftCode;
}
receive(msg: NFTOwnershipAssigned) {
let expectedNftAddress = calculateNFTAddress(self.nftItemIndex, self.nftCollectionAddress, self.nftCode); // or you can even store expectedNftAddress
require(expectedNftAddress == sender(), "NFT contract is not the sender");
// your logic of processing nft ownership assign notification
}
}

由于NFT项目的初始数据布局可能各不相同,第一种方法往往更合适。

转移 NFT 项目

要发送 NFT 项目转移,请使用 send()函数。

import "@stdlib/deploy";
message(0x5fcc3d14) NFTTransfer {
queryId: Int as uint64;
newOwner: Address; // address of the new owner of the NFT item.
responseDestination: Address; // address where to send a response with confirmation of a successful transfer and the rest of the incoming message coins.
customPayload: Cell? = null; // optional custom data. In most cases should be null
forwardAmount: Int as coins; // the amount of nanotons to be sent to the new owner.
forwardPayload: Slice as remaining; // optional custom data that should be sent to the new owner.
}
contract Example {
nftItemAddress: Address;
init(nftItemAddress: Address) {
self.nftItemAddress = nftItemAddress;
}
// ... add more code from previous examples ...
receive("transfer") {
send(SendParameters{
to: self.nftItemAddress,
value: ton("0.1"),
body: NFTTransfer{
queryId: 42,
// FIXME: Change this according to your needs
newOwner: sender(),
responseDestination: myAddress(),
customPayload: null,
forwardAmount: 1,
forwardPayload: rawSlice("F"), // precomputed beginCell().storeUint(0xF, 4).endCell().beginParse()
}.toCell(),
});
}
}

获取 NFT 静态信息

请注意,TON Blockchain 不允许合约相互调用 getters。 要从另一个合约接收数据,您必须交换消息。

message(0x2fcb26a2) NFTGetStaticData {
queryId: Int as uint64;
}
message(0x8b771735) NFTReportStaticData {
queryId: Int as uint64;
index: Int as uint256;
collection: Address;
}
struct NFTItemInitData {
index: Int as uint64;
collectionAddress: Address;
}
inline fun calculateNFTAddress(index: Int, collectionAddress: Address, nftCode: Cell): Address {
let initData = NFTItemInitData{
index,
collectionAddress,
};
return contractAddress(StateInit{code: nftCode, data: initData.toCell()});
}
contract Example {
nftCollectionAddress: Address;
nftItemIndex: Int as uint64;
nftCode: Cell;
init(nftCollectionAddress: Address, nftItemIndex: Int, nftCode: Cell) {
self.nftCollectionAddress = nftCollectionAddress;
self.nftItemIndex = nftItemIndex;
self.nftCode = nftCode;
}
// ... add more code from previous examples ...
receive("get static data") {
// FIXME: Put proper address("[NFT_ADDRESS]") here
let nftAddress = sender();
send(SendParameters{
to: nftAddress,
value: ton("0.1"),
body: NFTGetStaticData{
queryId: 42,
}.toCell(),
});
}
receive(msg: NFTReportStaticData) {
let expectedNftAddress = calculateNFTAddress(msg.index, msg.collection, self.nftCode);
require(expectedNftAddress == sender(), "NFT contract is not the sender");
// Save nft static data or do something
}
}

获取 NFT 版税参数

此处](https://github.com/ton-blockchain/TEPs/blob/master/text/0066-nft-royalty-standard.md)介绍了 NFT 版税参数。

message(0x693d3950) NFTGetRoyaltyParams {
queryId: Int as uint64;
}
message(0xa8cb00ad) NFTReportRoyaltyParams {
queryId: Int as uint64;
numerator: Int as uint16;
denominator: Int as uint16;
destination: Address;
}
contract Example {
nftCollectionAddress: Address;
init(nftCollectionAddress: Address) {
self.nftCollectionAddress = nftCollectionAddress;
}
// ... add more code from previous examples ...
receive("get royalty params") {
send(SendParameters{
to: self.nftCollectionAddress,
value: ton("0.1"),
body: NFTGetRoyaltyParams{
queryId: 42,
}.toCell(),
});
}
receive(msg: NFTReportRoyaltyParams) {
require(self.nftCollectionAddress == sender(), "NFT collection contract is not the sender");
// Do something with msg
}
}

NFT 集合方法

请注意,只有NFT所有者才能使用这些方法。

部署 NFT

message(0x1) NFTDeploy {
queryId: Int as uint64;
itemIndex: Int as uint64;
amount: Int as coins; // amount to sent when deploying nft
nftContent: Cell;
}
contract Example {
nftCollectionAddress: Address;
init(nftCollectionAddress: Address) {
self.nftCollectionAddress = nftCollectionAddress;
}
// ... add more code from previous examples ...
receive("deploy") {
send(SendParameters{
to: self.nftCollectionAddress,
value: ton("0.14"),
body: NFTDeploy{
queryId: 42,
itemIndex: 42,
amount: ton("0.1"),
nftContent: beginCell().endCell() // FIXME: Should be your content, mostly generated offchain
}.toCell(),
});
}
}

更改所有者

message(0x3) NFTChangeOwner {
queryId: Int as uint64;
newOwner: Address;
}
contract Example {
nftCollectionAddress: Address;
init(nftCollectionAddress: Address) {
self.nftCollectionAddress = nftCollectionAddress;
}
// ... add more code from previous examples ...
receive("change owner") {
send(SendParameters{
to: self.nftCollectionAddress,
value: ton("0.05"),
body: NFTChangeOwner{
queryId: 42,
// FIXME: Put proper address("NEW_OWNER_ADDRESS") here
newOwner: sender(),
}.toCell(),
});
}
}