XRP LedgerでNFTを触ってみる
XRP Ledger とは
XRP LedgerはBitcoinやEthereumなどと同じ分散型のパブリックブロックチェーンです。PoWやPoSとは異なる独自のコンセンサスアルゴリズムが用いられています。
EVMによるスマートコントラクトは搭載しておらず、スマートトランザクタ(プロトコルネイティブで提供されている機能)を拡張することで進化し続けています。執筆時点ではNFT機能はコミュニティによる投票中であり、その他にはAMMやXRPL独自の(狭義の)スマートコントラクトについての開発が進められています。
ネイティブトークンとしてXRPが存在し、その最小単位は1 drop(1 XRP = 1,000,000 drop)となっています。
NFT 機能について
これまでXRP LeddgerにはNFT機能が存在しませんでしたが、2021年5月にNik BougalisらによってXRPLにNFTを実装するための標準規格 XLS-20 が提案されました。その後Devnetのリリースなどを経て、執筆時点ではコミュニティによる投票を行なっています。
バリデータによる賛成票が80%超を2週間キープした場合、メインネットで有効化されます。
XRP LedgerでのNFT機能のメリットとして、十分にテストされたネイティブでのNFT機能のため、セキュリティリスクがEVMスマートコントラクトによるNFTよりも低いと考えられます。また、ネイティブでロイヤリティにも対応しており、クリエイターフレンドリーでもあります。
メインネットでの有効化の状況は以下から確認ができます。
NFTに関するトランザクションの種類
以下のようなトランザクションを利用することでNFTの発行や売買などが可能となっています。
NFTokenMint
NFTを発行するトランザクションです。
NFTokenCreateOffer
NFTの売却オファー/購入オファーを作成するトランザクションです。
NFTokenCancelOffer
NFTの売却オファー/購入オファーを取り下げるトランザクションです。
NFTokenAcceptOffer
NFTの売却オファー/購入オファーを承認するトランザクションです。
NFTokenBurn
NFTをバーンするトランザクションです。
1. NFTをミントする。
NFTを発行します。発行したNFTは発行時点では発行者が保有します。
import { Client, Wallet } from "xrpl";
const client = new Client("wss://s.devnet.rippletest.net:51233");
const wallet = Wallet.fromSeed("sncJTGw7U********************");
const mintResult = await client.submitAndWait(
{
TransactionType: "NFTokenMint",
Account: wallet.classicAddress,
TransferFee: 5 * 1000, // 5%
NFTokenTaxon: 0,
Flags: 1 + 8, // Burnable, Transferable
URI: convertStringToHex('ipfs://*********') // hex形式で指定
},
{ wallet }
);
2. 発行したNFTのIDを確認する。
XRP Ledger全体で一意に定められているNFTのIDを取得します。
パターン 1. アカウントの NFT 一覧から取得する
XRPLにはアカウントが保有する全てのNFTを取得するメソッド account_nfts
があります。
パターン1ではこのメソッドを使用してNFTを取得します。
const response = await client.request({
command: "account_nfts",
account: wallet.classicAddress,
});
// NFTokenが配列で格納されている。
// 注意: 発行順ではなくTokenID順で格納されている
console.log(response.result.account_nfts);
パターン 2. NFTokenMintのレスポンスから取得する
NFTのミントトランザクションのレスポンスには、そのトランザクションでXRPLのデータのどのようなオブジェクトに変更があったかを示すmetaフィールドが含まれています。
NFTのミントは NFTokenPage
へ影響を与え、NFTokenを追加します。
変更前と変更後を比較し、変更後にのみ存在するNFTokenが新規にミントしたNFTとなります。
const node =
mintResult.result.meta.AffectedNodes.find(
(n) => (n.ModifiedNode.LedgerEntryType || "") === "NFTokenPage"
).ModifiedNode || [];
// NFTokenMintトランザクション実行後の`NFTokenPage`に格納されているNFTokenIDの一覧を取得
const finalNFTokenIds = node.FinalFields.NFTokens.map(
(t) => t.NFToken.NFTokenID
);
// NFTokenMintトランザクション実行前の`NFTokenPage`に格納されているNFTokenIDの一覧を取得
const previousNFTokenIds = node.PreviousFields.NFTokens.map(
(t) => t.NFToken.NFTokenID
);
// // NFTokenMintトランザクション実行後にのみ存在するNFTokenIDを取得
const NFTokenID = finalNFTokenIds.find(
(token) => !previousNFTokenIds.includes(token)
);
console.log(NFTokenID);
3. 売却オファーを作成する。
XRPLには不要なトークンを他者に保有させることはできないという強い原則があり、受信者の許可なくNFTを送信することは出来ません。
そのため、NFTを転送する場合は、NFT保有者のオファーと受け取り側のオファーの承認が必要となります。
逆に受け取り側がオファーし、保有者がオファーを承認するということも可能です。
await client.submitAndWait(
{
TransactionType: "NFTokenCreateOffer",
Account: wallet.classicAddress,
Amount: xrpToDrops(100), // 100XRP Amountはdrop単位で指定
NFTokenID,
Flags: 1, // 売却オファーを作成する場合は1, 購入オファーを作成する場合は指定しない
},
{ wallet }
);
4. 購入者アカウントで売却オファーを受け入れる
// NFToken Offer IDを取得
const result = await client.request({
command: 'nft_sell_offer',
nft_id: NFTokenID,
})
// 指定したNFTのオファー一覧から受け入れるオファーを選択
const offerId = result.offers[0].nft_offer_index
// 売却オファーの承認
await client.submitAndWait({
TransactionType: 'NFTokenAcceptOffer',
Account: wallet.classicAddress,
NFTokenBuyOffer: offerId
}, { wallet })
まとめ
今回はXRP LedgerにはSBT機能や、他アカウントへのMint権限を委任する機能、マーケットプレイス向けのブローカー機能など多彩な機能が存在し、それら全てがスマートトランザクタとして利用可能です。スマートトランザクタとして実装されていることで、Mint時の Flags
フィールドを変えるだけとても簡単にSBT機能を利用できます。
XRP LedgerでのNFTの盛り上がりにも期待されています。
興味を持たれた方はXRP Ledger開発者のDiscordチャンネルへ是非お越しください!
日本語チャンネルもありますので、英語ができなくても大丈夫です!
Discussion