lesson-4_NFTの情報を確認できるようにしよう
🫣 NFT の情報を確認できるようにしよう
まずはNFT1つ1つの情報を見るための関数をつくります。nft_core.rsに移動して下のコードを追加しましょう。
[nft_core.rs]
+ use crate::*;
+
+ pub trait NonFungibleTokenCore {
+ fn nft_token(&self, token_id: TokenId) -> Option<JsonToken>;
+ }
+
+ #[near_bindgen]
+ impl NonFungibleTokenCore for Contract {
+ // get specified token info
+ fn nft_token(&self, token_id: TokenId) -> Option<JsonToken> {
+ if let Some(token) = self.tokens_by_id.get(&token_id) {
+ let metadata = self.token_metadata_by_id.get(&token_id).unwrap();
+ Some(JsonToken {
+ owner_id: token.owner_id,
+ metadata,
+ })
+ } else {
+ None
+ }
+ }
+ }
ひとつずつ見ていきましょう。まずはNonFungibleTokenCore
というトレイトにnft_token
という関数があることを宣言する。ここでは引き数と返り値だけで大丈夫です。
pub trait NonFungibleTokenCore {
fn nft_token(&self, token_id: TokenId) -> Option<JsonToken>;
}
次の部分ではnft_token関数
の中身を記述します。ここでは引数であるtokenのidに対してmetadataが存在するのかを確かめて、ある場合はそれを返すという処理をしています。
#[near_bindgen]
impl NonFungibleTokenCore for Contract {
// get specified token info
fn nft_token(&self, token_id: TokenId) -> Option<JsonToken> {
if let Some(token) = self.tokens_by_id.get(&token_id) {
let metadata = self.token_metadata_by_id.get(&token_id).unwrap();
Some(JsonToken {
owner_id: token.owner_id,
metadata,
})
} else {
None
}
}
}
これによってそれぞれのtokenのmetadataを見れるようになりましたが、walletがNFTを表示できるようにするための関数であるnft_tokens_for_owner関数
がまだ実装できていないのでenumeration.rs
に移動して下のコードを追加しましょう。
[enumeration.rs]
+ use crate::*;
+
+ #[near_bindgen]
+ impl Contract {
+ pub fn nft_total_supply(&self) -> U128 {
+ U128(self.token_metadata_by_id.len() as u128)
+ }
+
+ pub fn nft_tokens(&self, from_index: Option<U128>, limit: Option<u64>) -> Vec<JsonToken> {
+ let start = u128::from(from_index.unwrap_or(U128(0)));
+ self.token_metadata_by_id
+ .keys()
+ .skip(start as usize)
+ .take(limit.unwrap_or(50) as usize)
+ .map(|token_id| self.nft_token(token_id.clone()).unwrap())
+ .collect()
+ }
+
+ // get number of tokens for specified owner
+ pub fn nft_supply_for_owner(&self, account_id: AccountId) -> U128 {
+ let tokens_for_kind_set = self.tokens_per_owner.get(&account_id);
+ if let Some(tokens_for_kind_set) = tokens_for_kind_set {
+ U128(tokens_for_kind_set.len() as u128)
+ } else {
+ U128(0)
+ }
+ }
+
+ pub fn nft_tokens_for_owner(
+ &self,
+ account_id: AccountId,
+ from_index: Option<U128>,
+ limit: Option<u64>,
+ ) -> Vec<JsonToken> {
+ let tokens_for_owner_set = self.tokens_per_owner.get(&account_id);
+ let tokens = if let Some(tokens_for_owner_set) = tokens_for_owner_set {
+ tokens_for_owner_set
+ } else {
+ return vec![];
+ };
+
+ let start = u128::from(from_index.unwrap_or(U128(0)));
+ tokens
+ .iter()
+ .skip(start as usize)
+ .take(limit.unwrap_or(50) as usize)
+ .map(|token_id| self.nft_token(token_id.clone()).unwrap())
+ .collect()
+ }
+ }
最初のnft_total_supply関数
ではコントラクトに保存されているNFTの数を取得できます。
次のnft_tokens
ではコントラクトに保管されている全てのNFTのmetadataが得られます。
pub fn nft_total_supply(&self) -> U128 {
U128(self.token_metadata_by_id.len() as u128)
}
pub fn nft_tokens(&self, from_index: Option<U128>, limit: Option<u64>) -> Vec<JsonToken> {
let start = u128::from(from_index.unwrap_or(U128(0)));
self.token_metadata_by_id
.keys()
.skip(start as usize)
.take(limit.unwrap_or(50) as usize)
.map(|token_id| self.nft_token(token_id.clone()).unwrap())
.collect()
}
この関数では特定の所有者が持つNFTの数を取得できます。これはwallet上での表示にも関わってくるので書き漏れのないように特に気をつけてください。
pub fn nft_supply_for_owner(&self, account_id: AccountId) -> U128 {
let tokens_for_kind_set = self.tokens_per_owner.get(&account_id);
if let Some(tokens_for_kind_set) = tokens_for_kind_set {
U128(tokens_for_kind_set.len() as u128)
} else {
U128(0)
}
}
引数としてはユーザーのWallet Idをとります。from_index、limit
は対象のユーザーがたくさんNFTを持っているときにNFTのリストのどこからどこまでを取得するかを指定するために用意されています。
返り値としてmetadataとownerのidが入っているJsonToken
型のベクターが返ってきます。
pub fn nft_tokens_for_owner(
&self,
account_id: AccountId,
from_index: Option<U128>,
limit: Option<u64>,
)-> Vec<JsonToken>
内容としてはまず所有者のtokenのidからtokenのidがリスト化されたベクターをとってきます。
その次の処理でtokenのidのリストの中身が無い場合は新しくインスタンス化します。
最後に先ほど作成したnft_token関数
を利用してtokenのmetadataとその所有者を紐づけた情報を返します。
pub fn nft_tokens_for_owner(
&self,
account_id: AccountId,
from_index: Option<U128>,
limit: Option<u64>,
) -> Vec<JsonToken> {
let tokens_for_owner_set = self.tokens_per_owner.get(&account_id);
let tokens = if let Some(tokens_for_owner_set) = tokens_for_owner_set {
tokens_for_owner_set
} else {
return vec![];
};
let start = u128::from(from_index.unwrap_or(U128(0)));
tokens
.iter()
.skip(start as usize)
.take(limit.unwrap_or(50) as usize)
.map(|token_id| self.nft_token(token_id.clone()).unwrap())
.collect()
}
これでやっとmint機能とそれをwalletとターミナル上で確認できるようになったので次は実際にコントラクトをdeployして、mintしてみましょう!
🤞 mint してみよう
mintをしたいところですが、mintができているかを確認するためにまずはNEARのTestnetで自分のWalletを作成する必要があります。 こちらから作成してください。
まず、packages/contract
に移動します。
walletのidをコピーして下のコマンドのYOUR_WALLET_ID
に入れてターミナルで実行させてく ださい。
export NFT_CONTRACT_ID=YOUR_WALLET_ID
下のコマンドをターミナルを実行させてきちんとNFT_CONTRACT_ID
という変数にあなたのWallet Idが入っているかを確認してみましょう。
echo $NFT_CONTRACT_ID
確認ができたら、下のコマンドをターミナルを実行させてログインしましょう。
near login
次にpackages/contract/package.json
のscript
部分を以下のように編集してください。
"scripts": {
"build":"set -e && RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release",
"deploy":"near deploy --wasm-file target/wasm32-unknown-unknown/release/near_election_dapp_contract.wasm --accountId $NFT_CONTRACT_ID",
"test": "cargo test"
},
その後、ターミナル上で、下記を実行してみましょう。
yarn contract build
yarn contract deploy