如何让我的 NFT 在 NEAR 钱包(AssemblyScript)中可见?
How can I make my NFT visible in the NEAR wallet (AssemblyScript)?
我正在尝试实现我自己的 NFT-contract、following this tutorial on NEAR, and the Non-Fungible Token (NEP-171) specifications。教程在 Rust
中,但我正在尝试用 AssemblyScript
做一些类似的事情。我想如果我用正确的名称和签名实现这些方法,NEAR 钱包就可以在我的 NFT-contract 上调用相应的方法(例如 nft_tokens_for_owner
)。我只是想知道我是否遗漏了什么,或者我是否对它应该如何工作有错误的理解。
我已经铸造了一个 NFT-token,使用我合约中的 nft_mint
方法,使用我自己的测试网帐户。可以找到交易 here。但是,NFT 没有显示在我的测试网钱包的“收藏品”选项卡中。
我的合同(index.ts)是这样的:
import { PersistentMap } from 'near-sdk-as';
import { Token, TokenMetadata } from './reit-token';
@nearBindgen
class NFTContractMetadata {
spec: string; // required, essentially a version like "nft-1.0.0"
name: string; // required, ex. "Mochi Rising — Digital Edition" or "Metaverse 3"
symbol: string; // required, ex. "MOCHI"
icon: string | null; // Data URL
base_uri: string | null; // Centralized gateway known to have reliable access to decentralized storage assets referenced by `reference` or `media` URLs
reference: string | null; // URL to a JSON file with more info
reference_hash: string | null; // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
}
@nearBindgen
export class Contract {
//keeps track of the metadata for the contract
metadata: NFTContractMetadata = {
spec: 'reit-token-0.0.0',
name: 'Reit Token',
symbol: 'REIT',
icon: null,
base_uri: null,
reference: null,
reference_hash: null,
};
//contract owner
owner_id: string; // Not sure if this is relevant for the contract itself
//keeps track of all the token IDs for a given account
tokens_per_owner: PersistentMap<string, Array<string>> = new PersistentMap<
string,
Array<string>
>('tokens_pr_owner');
//keeps track of the token struct for a given token ID
tokens_by_id: PersistentMap<string, Token> = new PersistentMap<string, Token>(
'tokens_by_id'
);
//keeps track of the token metadata for a given token ID
token_metadata_by_id: PersistentMap<string, TokenMetadata> =
new PersistentMap<string, TokenMetadata>('token_metadata_by_id');
nft_tokens_for_owner(account_id: string): Array<Token> {
const tokenIds: string[] = this.tokens_per_owner.getSome(account_id);
const tokens: Array<Token> = new Array<Token>();
for (let i = 0; i < tokenIds.length; ++i) {
const token: Token = this.tokens_by_id.getSome(tokenIds[i]);
tokens.push(token);
}
return tokens;
}
nft_mint(
token_id: string,
metadata: TokenMetadata,
receiver_id: string
): void {
// assert(
// this.tokens_by_id.contains(token_id),
// 'ID is already taken, create new ID'
// );
const token = new Token(token_id, metadata, receiver_id);
const tokens: Array<string> = new Array<string>();
tokens.push(token_id);
this.tokens_per_owner.set(receiver_id, tokens);
this.tokens_by_id.set(token_id, token);
this.token_metadata_by_id.set(token_id, token.metadata);
}
里面reit-token.ts
import { ContractPromise } from 'near-sdk-as';
// implementation based on NEP-171
// https://nomicon.io/Standards/NonFungibleToken/Core.html
@nearBindgen
export class TokenMetadata {
title: string; // ex. "Arch Nemesis: Mail Carrier" or "Parcel #5055"
description: string; // free-form description
media: string; // URL to associated media, preferably to decentralized, content-addressed storage
media_hash: string; // Base64-encoded sha256 hash of content referenced by the `media` field. Required if `media` is included.
copies: number; // number of copies of this set of metadata in existence when token was minted.
issued_at: number; // When token was issued or minted, Unix epoch in milliseconds
expires_at: number; // When token expires, Unix epoch in milliseconds
starts_at: number; // When token starts being valid, Unix epoch in milliseconds
updated_at: number; // When token was last updated, Unix epoch in milliseconds
extra: string; // anything extra the NFT wants to store on-chain. Can be stringified JSON.
reference: string; // URL to an off-chain JSON file with more info.
reference_hash: string; // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
}
@nearBindgen
export class Token {
id: string;
owner_id: string;
metadata: TokenMetadata;
constructor(token_id: string, metadata: TokenMetadata, receiver_id: string) {
this.id = token_id;
this.metadata = metadata;
this.owner_id = receiver_id;
}
}
@nearBindgen
export class ReitToken {
token: Token;
constructor(token_id: string, metadata: TokenMetadata, receiver_id: string) {
this.token = { id: token_id, metadata: metadata, owner_id: receiver_id };
}
// --- view methods --- //
nft_token(): Token {
return this.token;
}
// --- change methods --- //
nft_transfer(
receiver_id: string,
token_id: string,
approval_id: number,
memo: string
): void {
// assert(false, 'nft_transfer not implemented');
}
nft_transfer_call(
receiver_id: string,
token_id: string,
approval_id: number,
memo: string,
msg: string
): ContractPromise {
// assert(false, 'nft_transfer_call not implemented');
return ContractPromise.create('', '', {}, 1);
}
}
四处询问后,我被指向两个不同的 GitHub 存储库,它们在 AssemblyScript 中实现了 NFT 代币智能合约。
- https://github.com/dOrgTech/proof-of-attendance
- https://github.com/vgrichina/humanguild-nft/tree/lisbon
在浏览了这些存储库之后,我注意到我的合约距离能够在钱包中显示我的 NFT 代币并不遥远。我不得不再实现一个功能,nft_metadata()
.
我的合同中确实有元数据,但作为变量,metadata
。在 nft_metadata()
中返回相同的元数据似乎可以解决问题
@nearBindgen
class NFTContractMetadata {
constructor(
public spec: string = 'reit-token-0.0.0', // required, essentially a version like "nft-1.0.0"
public name: string = 'Reit Token', // required, ex. "Mochi Rising — Digital Edition" or "Metaverse 3"
public symbol: string = 'REIT', // required, ex. "MOCHI"
public icon: string = '', // Data URL
public base_uri: string = '', // Centralized gateway known to have reliable access to decentralized storage assets referenced by `reference` or `media` URLs
public reference: string = '', // URL to a JSON file with more info
public reference_hash: string = '' // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
) {}
}
@nearBindgen
export class Contract {
// ...
nft_metadata(): NFTContractMetadata {
return new NFTContractMetadata();
}
// ...
}
我在测试时确实用一个新的 (transaction found here) 覆盖了我现有的 NFT,在这里,它在 NEAR testnet 钱包中可见
我正在尝试实现我自己的 NFT-contract、following this tutorial on NEAR, and the Non-Fungible Token (NEP-171) specifications。教程在 Rust
中,但我正在尝试用 AssemblyScript
做一些类似的事情。我想如果我用正确的名称和签名实现这些方法,NEAR 钱包就可以在我的 NFT-contract 上调用相应的方法(例如 nft_tokens_for_owner
)。我只是想知道我是否遗漏了什么,或者我是否对它应该如何工作有错误的理解。
我已经铸造了一个 NFT-token,使用我合约中的 nft_mint
方法,使用我自己的测试网帐户。可以找到交易 here。但是,NFT 没有显示在我的测试网钱包的“收藏品”选项卡中。
我的合同(index.ts)是这样的:
import { PersistentMap } from 'near-sdk-as';
import { Token, TokenMetadata } from './reit-token';
@nearBindgen
class NFTContractMetadata {
spec: string; // required, essentially a version like "nft-1.0.0"
name: string; // required, ex. "Mochi Rising — Digital Edition" or "Metaverse 3"
symbol: string; // required, ex. "MOCHI"
icon: string | null; // Data URL
base_uri: string | null; // Centralized gateway known to have reliable access to decentralized storage assets referenced by `reference` or `media` URLs
reference: string | null; // URL to a JSON file with more info
reference_hash: string | null; // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
}
@nearBindgen
export class Contract {
//keeps track of the metadata for the contract
metadata: NFTContractMetadata = {
spec: 'reit-token-0.0.0',
name: 'Reit Token',
symbol: 'REIT',
icon: null,
base_uri: null,
reference: null,
reference_hash: null,
};
//contract owner
owner_id: string; // Not sure if this is relevant for the contract itself
//keeps track of all the token IDs for a given account
tokens_per_owner: PersistentMap<string, Array<string>> = new PersistentMap<
string,
Array<string>
>('tokens_pr_owner');
//keeps track of the token struct for a given token ID
tokens_by_id: PersistentMap<string, Token> = new PersistentMap<string, Token>(
'tokens_by_id'
);
//keeps track of the token metadata for a given token ID
token_metadata_by_id: PersistentMap<string, TokenMetadata> =
new PersistentMap<string, TokenMetadata>('token_metadata_by_id');
nft_tokens_for_owner(account_id: string): Array<Token> {
const tokenIds: string[] = this.tokens_per_owner.getSome(account_id);
const tokens: Array<Token> = new Array<Token>();
for (let i = 0; i < tokenIds.length; ++i) {
const token: Token = this.tokens_by_id.getSome(tokenIds[i]);
tokens.push(token);
}
return tokens;
}
nft_mint(
token_id: string,
metadata: TokenMetadata,
receiver_id: string
): void {
// assert(
// this.tokens_by_id.contains(token_id),
// 'ID is already taken, create new ID'
// );
const token = new Token(token_id, metadata, receiver_id);
const tokens: Array<string> = new Array<string>();
tokens.push(token_id);
this.tokens_per_owner.set(receiver_id, tokens);
this.tokens_by_id.set(token_id, token);
this.token_metadata_by_id.set(token_id, token.metadata);
}
里面reit-token.ts
import { ContractPromise } from 'near-sdk-as';
// implementation based on NEP-171
// https://nomicon.io/Standards/NonFungibleToken/Core.html
@nearBindgen
export class TokenMetadata {
title: string; // ex. "Arch Nemesis: Mail Carrier" or "Parcel #5055"
description: string; // free-form description
media: string; // URL to associated media, preferably to decentralized, content-addressed storage
media_hash: string; // Base64-encoded sha256 hash of content referenced by the `media` field. Required if `media` is included.
copies: number; // number of copies of this set of metadata in existence when token was minted.
issued_at: number; // When token was issued or minted, Unix epoch in milliseconds
expires_at: number; // When token expires, Unix epoch in milliseconds
starts_at: number; // When token starts being valid, Unix epoch in milliseconds
updated_at: number; // When token was last updated, Unix epoch in milliseconds
extra: string; // anything extra the NFT wants to store on-chain. Can be stringified JSON.
reference: string; // URL to an off-chain JSON file with more info.
reference_hash: string; // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
}
@nearBindgen
export class Token {
id: string;
owner_id: string;
metadata: TokenMetadata;
constructor(token_id: string, metadata: TokenMetadata, receiver_id: string) {
this.id = token_id;
this.metadata = metadata;
this.owner_id = receiver_id;
}
}
@nearBindgen
export class ReitToken {
token: Token;
constructor(token_id: string, metadata: TokenMetadata, receiver_id: string) {
this.token = { id: token_id, metadata: metadata, owner_id: receiver_id };
}
// --- view methods --- //
nft_token(): Token {
return this.token;
}
// --- change methods --- //
nft_transfer(
receiver_id: string,
token_id: string,
approval_id: number,
memo: string
): void {
// assert(false, 'nft_transfer not implemented');
}
nft_transfer_call(
receiver_id: string,
token_id: string,
approval_id: number,
memo: string,
msg: string
): ContractPromise {
// assert(false, 'nft_transfer_call not implemented');
return ContractPromise.create('', '', {}, 1);
}
}
四处询问后,我被指向两个不同的 GitHub 存储库,它们在 AssemblyScript 中实现了 NFT 代币智能合约。
- https://github.com/dOrgTech/proof-of-attendance
- https://github.com/vgrichina/humanguild-nft/tree/lisbon
在浏览了这些存储库之后,我注意到我的合约距离能够在钱包中显示我的 NFT 代币并不遥远。我不得不再实现一个功能,nft_metadata()
.
我的合同中确实有元数据,但作为变量,metadata
。在 nft_metadata()
中返回相同的元数据似乎可以解决问题
@nearBindgen
class NFTContractMetadata {
constructor(
public spec: string = 'reit-token-0.0.0', // required, essentially a version like "nft-1.0.0"
public name: string = 'Reit Token', // required, ex. "Mochi Rising — Digital Edition" or "Metaverse 3"
public symbol: string = 'REIT', // required, ex. "MOCHI"
public icon: string = '', // Data URL
public base_uri: string = '', // Centralized gateway known to have reliable access to decentralized storage assets referenced by `reference` or `media` URLs
public reference: string = '', // URL to a JSON file with more info
public reference_hash: string = '' // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
) {}
}
@nearBindgen
export class Contract {
// ...
nft_metadata(): NFTContractMetadata {
return new NFTContractMetadata();
}
// ...
}
我在测试时确实用一个新的 (transaction found here) 覆盖了我现有的 NFT,在这里,它在 NEAR testnet 钱包中可见