SolanaのToken-2022 ProgramのMetadataを検証してみた
こんにちは。次世代システム研究室のL.W.です。
前篇のまとめのところではToken-2022プログラムを言及しましたが、以来ずっとToken-2022プログラムの進展を注目しています。
Token-2022プログラムは今年2024年こそ、メインネットに展開されます。ステーブルコイン 、DeFi、NFTの領域での大活躍を期待されています。
今回は、Token-2022プログラムのトークンのメタデータ(Metadata)について調査して、検証してみましたが、共有します。
目次
1.Token-2022 Programについて
SolanaのToken-2022 Programは、開発者により複雑なトークン経済と制御を可能にする、より柔軟で拡張可能なトークン標準を目指しています。既存のToken Programを拡張した進化版のトークンプログラムです。これは、Solanaブロックチェーン上でのファンジブルトークン(交換可能トークン、FT)とノンファンジブルトークン(非交換可能トークン、NFT)のための共通の実装を定義しています。Token-2022 Programは、以前のToken Programに提供された機能のスーパーセットとして位置づけられています。既存のToken Programの上に構築され、開発者に向けて拡張された柔軟性と追加機能を提供しながら、現在のトークンの安全性を損なわないように設計されています。
ミントアカウントとトークンアカウントに色々な有用な機能が追加されています。特に、ミントアカウントに拡張された主な機能は以下の通りです。
1.1. PermanentDelegate
この拡張機能は、ミントアカウントの指定された永久代理(Permanent Delegate)を設定することを可能にします。この永久代理は、そのミントの全トークンアカウントに対して無制限の代理権限を持ち、トークンを制限なく焼却(burn)または転送(transfer)することができます。永久代理はそのミントの全トークンアカウントの実質的なグローバルオーナーとなります。永久代理の鍵が危険にさらされると、攻撃者はそのミントの全トークンアカウントを完全にコントロールすることができます。
1.2. DefaultAccountState
ミントの作成者は、自分のトークンを誰が使用できるかを制限することを望むかもしれません。この問題に対処するため、DefaultAccountState
拡張を使用して、すべての新しいトークンアカウントを凍結状態に強制することができます。これにより、ユーザーは最終的に何らかのサービスとやり取りしてアカウントを凍結解除し、トークンを使用する必要があります。1.3. MintCloseAuthority
トークンの所有者はトークンアカウントを閉じることができますが、Token Programのミントアカウントは閉じることができません。Token-2022では、MintCloseAuthority
拡張を初期化してからミントを初期化することにより、ミントを閉じることが可能になります。これで、ミントアカウントのSOL残高を回収することも可能となります。イーサリアムのSelfdestructと同じ機能だと理解していただければと思います。
1.4. TransferFee
トークンプログラムでは、すべての転送に手数料を課すことは不可能です。イーサリアムでもこのような機能も存在しないはずです。Token-2022では、ミントに転送手数料を設定でき、プロトコルレベルで手数料が課されます。転送の際には、受信者アカウントから一定の量が差し引かれ、受信者はそれにアクセスすることができません。これらのトークンはミントの別の権限によって保持されることができます。
1.5. MetadataPointer
solana account 41kjF4dSVkfac4s4XijxW1TxppZXzNdyu4JetQxMTnt7 Public Key: 41kjF4dSVkfac4s4XijxW1TxppZXzNdyu4JetQxMTnt7 Balance: 0.01561672 SOL Owner: metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s Executable: false Rent Epoch: 18446744073709551615 Length: 679 (0x2a7) bytes 0000: 04 9d 45 cf 13 6b ae f1 9b 87 31 a6 ef 2d e5 6b ..E..k....1..-.k 0010: 22 21 7e 92 ed 43 f3 7b 4f 9d 75 65 0e 2f 12 a3 "!~..C.{O.ue./.. 0020: ac 56 7f 14 ee 44 a9 26 70 5f 80 0c 9b 2b 23 be .V...D.&p_...+#. 0030: b6 3d 5d 86 da 76 91 34 27 20 f5 31 fa 10 cb 9b .=]..v.4' .1.... 0040: 0c 20 00 00 00 6c 69 77 65 69 20 74 6f 6b 65 6e . ...liwei token 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0060: 00 00 00 00 00 0a 00 00 00 4c 49 57 00 00 00 00 .........LIW.... 0070: 00 00 00 c8 00 00 00 68 74 74 70 73 3a 2f 2f 73 .......https://s 0080: 74 61 62 6c 65 63 6f 69 6e 2e 7a 2e 63 6f 6d 2f tablecoin.z.com/ 0090: 2e 77 65 6c 6c 2d 6b 6e 6f 77 6e 2f 7a 75 73 64 .well-known/zusd 00a0: 2e 6a 73 6f 6e 00 00 00 00 00 00 00 00 00 00 00 .json........... 00b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0140: 00 00 01 01 01 ff 01 02 00 00 00 00 00 00 00 00 ................ 0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 02a0: 00 00 00 00 00 00 01 ....... ----------------------------------------------------------------------------------------------------------------------------------------------- spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --metadata-address 41kjF4dSVkfac4s4XijxW1TxppZXzNdyu4JetQxMTnt7 Creating token 5V5vb4tv7W7H7j3DhqLT8sqUowAo2RS9RSXz9gxXXM1D under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb Address: 5V5vb4tv7W7H7j3DhqLT8sqUowAo2RS9RSXz9gxXXM1D Decimals: 9 Signature: VddgFg2nEnmmeaCzgmjnGQkSSZdDiNcRfgEDDspcQZSqm4Bt3eu82HT3a3ARDDiTpeZpnCGFaFYzNU6ucsMsU1p
Solanaブロックチェーンのトークンに関連するメタデータは、主にそのトークンの特性や情報を記述しています。一般的に含まれるのは、name(トークンの名前)、symbol(トークンを表す短い識別子)、uri(トークンと関わるicon、イメージ、アニメーションなど)、attributes(トークンに関連する追加の特性や属性)となります。
特に、NFT(Non-Fungible Token)の場合、メタデータには作品の作者、作品の説明、アートワークのURL、特別な属性や希少性などの情報が含まれることが多いです。これらのメタデータは、トークンの価値や意味を理解するのに重要な役割を果たします。
1.6. TokenMetadata
トークンメタデータの使用を容易にするため、Token-2022は、ミント作成者がトークンのメタデータを直接ミントアカウントに含めることを可能にします。メタデータ拡張機能は、メタデータポインタ拡張機能(MetadataPointer)と直接連携する必要があります。ミントの作成中に、メタデータポインタ拡張機能を追加する際、これをミント自体を指すように設定する必要があります。
spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-metadata Creating token HzxfBLpwHs8ixQxLuStBhEYexQcB8PmpBxcdP6D8t1c3 under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb To initialize metadata inside the mint, please run `spl-token initialize-metadata HzxfBLpwHs8ixQxLuStBhEYexQcB8PmpBxcdP6D8t1c3 <YOUR_TOKEN_NAME> <YOUR_TOKEN_SYMBOL> <YOUR_TOKEN_URI>`, and sign with the mint authority. Address: HzxfBLpwHs8ixQxLuStBhEYexQcB8PmpBxcdP6D8t1c3 Decimals: 9 Signature: 4RKtT4EDoRGEfVFYDAKV9MC5StqECD2h15apHMjreSYZb7tvsJYKeE2duLBpZrHwjhiTpQyf14MWMXF6WXFzGGre ------------------------------------------------------------------------------------------------------------------------- spl-token initialize-metadata HzxfBLpwHs8ixQxLuStBhEYexQcB8PmpBxcdP6D8t1c3 NNN SSS https://stablecoin.z.com/.well-known/zusd.json Signature: 3YBRPA14xbRY2aJLQACBdueAo4hgNKoJUfo6YwBDdQpon2GEtQ6GJb9Zzg7BKJS91BzZCmvoEtpGRX5GiuzBMNdJ ------------------------------------------------------------------------------------------------------------------------- solana account HzxfBLpwHs8ixQxLuStBhEYexQcB8PmpBxcdP6D8t1c3 Public Key: HzxfBLpwHs8ixQxLuStBhEYexQcB8PmpBxcdP6D8t1c3 Balance: 0.00346608 SOL Owner: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb Executable: false Rent Epoch: 18446744073709551615 Length: 370 (0x172) bytes 0000: 01 00 00 00 9d 45 cf 13 6b ae f1 9b 87 31 a6 ef .....E..k....1.. 0010: 2d e5 6b 22 21 7e 92 ed 43 f3 7b 4f 9d 75 65 0e -.k"!~..C.{O.ue. 0020: 2f 12 a3 ac 00 00 00 00 00 00 00 00 09 01 00 00 /............... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00a0: 00 00 00 00 00 01 12 00 40 00 9d 45 cf 13 6b ae [email protected]. 00b0: f1 9b 87 31 a6 ef 2d e5 6b 22 21 7e 92 ed 43 f3 ...1..-.k"!~..C. 00c0: 7b 4f 9d 75 65 0e 2f 12 a3 ac fc 94 07 a8 c6 b9 {O.ue./......... 00d0: bf e7 b8 87 22 9d 7a ee 03 7e 83 75 2e cb 10 d3 ....".z..~.u.... 00e0: 97 10 b6 14 0f 96 3a ca 11 18 13 00 84 00 9d 45 ......:........E 00f0: cf 13 6b ae f1 9b 87 31 a6 ef 2d e5 6b 22 21 7e ..k....1..-.k"!~ 0100: 92 ed 43 f3 7b 4f 9d 75 65 0e 2f 12 a3 ac fc 94 ..C.{O.ue./..... 0110: 07 a8 c6 b9 bf e7 b8 87 22 9d 7a ee 03 7e 83 75 ........".z..~.u 0120: 2e cb 10 d3 97 10 b6 14 0f 96 3a ca 11 18 03 00 ..........:..... 0130: 00 00 4e 4e 4e 03 00 00 00 53 53 53 2e 00 00 00 ..NNN....SSS.... 0140: 68 74 74 70 73 3a 2f 2f 73 74 61 62 6c 65 63 6f https://stableco 0150: 69 6e 2e 7a 2e 63 6f 6d 2f 2e 77 65 6c 6c 2d 6b in.z.com/.well-k 0160: 6e 6f 77 6e 2f 7a 75 73 64 2e 6a 73 6f 6e 00 00 nown/zusd.json.. 0170: 00 00 ..
2.今までのMetadataの付け方
2.1. Metaplexのトークンメタデータプログラム
トークンメタデータプログラムは、Solanaブロックチェーン上のNFTや通常のトークン(FT)にメタデータを付けるための重要なプログラムです。うちには、Metaplexの「Token Metadata」プログラムは事実上の標準になっています。Metaplexの「Token Metadata」プログラムで個々のミンチアカウントに対応するPDAを生成して、そのPDAアカウントにメタデータを記入することです。特にイメージ、アニメなどサイズ大きいコンテンツの場合、直接にアカウントに記入するのはコストが掛かる、そして、制限もあるので、off-chainのjsonの形で保持するのは一般的です。
出典:https://docs.metaplex.com/programs/token-metadata/overview
2.2. デモ
2.2.1. Tokenー2022 Program でミントアカウントを生成する
spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token Creating token Hw5ym6gPfEqAdR2RWWNZoPDrL16YfreRb9necw8nC728 under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb Address: Hw5ym6gPfEqAdR2RWWNZoPDrL16YfreRb9necw8nC728 Decimals: 9 Signature: kpV9uJrD4dNnnJUjFQW1LjNaL7WBx7ZMHAXFFtoxgayMfRYw4ukoDDbuR7bRSHfEs58ePoGu51FDVK17enF8ChM
2.2.2. Metaplexでメタデータを付けるため、スクリプトを作成する。ファイル名はset_metadata_for_spl_token_2022.tsとする。
import { createV1, updateV1 ,Collection, Creator, Uses, findMetadataPda, CreateV1InstructionAccounts, CreateV1InstructionData, TokenStandard, CollectionDetails, PrintSupply} from "@metaplex-foundation/mpl-token-metadata"; import * as web3 from "@solana/web3.js"; import { PublicKey, createSignerFromKeypair, none, percentAmount, publicKey, signerIdentity, some } from "@metaplex-foundation/umi"; import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'; import { fromWeb3JsKeypair, fromWeb3JsPublicKey} from '@metaplex-foundation/umi-web3js-adapters'; import * as bs58 from "bs58"; const SPL_TOKEN_2022_PROGRAM_ID: PublicKey = publicKey( 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' ); export function loadWalletKey(keypairFile:string): web3.Keypair { const fs = require("fs"); const loaded = web3.Keypair.fromSecretKey( new Uint8Array(JSON.parse(fs.readFileSync(keypairFile).toString())), ); return loaded; } async function main(){ console.log("set metadata for spl-token-2022!"); const myKeypair = loadWalletKey("id.json"); const mintP = process.argv[2]; const mint = new web3.PublicKey(mintP); const umi = createUmi("https://api.devnet.solana.com"); const signer = createSignerFromKeypair(umi, fromWeb3JsKeypair(myKeypair)) umi.use(signerIdentity(signer, true)) const ourMetadata = { name: "liwei token", symbol: "LIW", uri: "https://stablecoin.z.com/.well-known/zusd.json", } const metaaddress = findMetadataPda(umi,{mint: fromWeb3JsPublicKey(mint)}) const onChainData = { ...ourMetadata, // we don't need that sellerFeeBasisPoints: percentAmount(0,2), creators: none<Creator[]>(), collection: none<Collection>(), uses: none<Uses>(), } const accounts: CreateV1InstructionAccounts = { metadata: metaaddress, mint: fromWeb3JsPublicKey(mint), splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID, } const data: CreateV1InstructionData = { ...onChainData, isMutable: true, discriminator: 0, tokenStandard: TokenStandard.Fungible, collectionDetails: none<CollectionDetails>(), ruleSet: none<PublicKey>(), createV1Discriminator: 0, primarySaleHappened: true, decimals: none<number>(), printSupply: none<PrintSupply>(), } const txid = await createV1(umi, {...accounts, ...data}).sendAndConfirm(umi); console.log('set metadata success! ', bs58.encode(txid.signature)) } main();
2.2.3. Metaplexでメタデータとやり取りし、ミントアカウントのメタデータを付ける。
ts-node set_metadata_for_spl_token_2022.ts Hw5ym6gPfEqAdR2RWWNZoPDrL16YfreRb9necw8nC728 set metadata for spl-token-2022! set metadata success! 4TPfoWLYT2nwADus5n1mcCmDQDBm2dRNsYaZZLrKQRTALqm4tdt13tj7WKjLUGnioa4qrP8VMoSsDY3o94y68SiH
2.2.4. solscanで確認する
期待通りに、設定できたことが確認できます。3.Token-2022 ProgramのトークンにMetaplexとTokenMetadataの拡張を両方同時備えるか検証する
solscanで表示しているトークンのicon、nameとsymbolは一体どこからどのように取得したか、皆さんが考えたことがありますか。該当アカウントからメタデータのPDAのアカウントを取得し、PDAアカウントでmetadata情報が記載されてあります。metadata情報のuriの値でjsonファイルを取得し、jsonファイルから必要な情報を取得することができます。
これからToken-2022 Program は公式的に推奨されます。Token-2022のMetadataPointerとTokenMetadataの拡張を思い出してください。つまり、PDAアカウントを介さずに直接ミントアカウントにmetadata情報を記入することが可能となります。
これで、solscanで表示する内容はミントアカウントから取得することも可能となります。(※今の時点ではまだsolscanよりサポートしていない)
例え一つのミントアカウントには、MetaplexとTokenMetadataの拡張で両方のmetadataが付けられたら、一体どっちが基準か、ユーザには困惑をもたらすかねないですね。両方同時に備えることをコントラクトラベルで避けるべきです。
MetaplexとTokenMetadataの拡張が同時に備えるか検証してみましょう。
3.1.1. TokenMetadataの拡張でメタデータを付ける
spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-metadata Creating token suDf4QQF3PSEnqVBTncndsS4Z58QoY9An135DwQiiXS under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb To initialize metadata inside the mint, please run `spl-token initialize-metadata suDf4QQF3PSEnqVBTncndsS4Z58QoY9An135DwQiiXS <YOUR_TOKEN_NAME> <YOUR_TOKEN_SYMBOL> <YOUR_TOKEN_URI>`, and sign with the mint authority. Address: suDf4QQF3PSEnqVBTncndsS4Z58QoY9An135DwQiiXS Decimals: 9 Signature: 4N893DVuYBPAbhXhFFPE6447iv27Jb2YvnuVHU8qx5gUgRWEn6QYsNy56D81wvJnXt1rHLRFtQSPiJakk9E3aWEQ ーーーーーーーーーーーー spl-token initialize-metadata suDf4QQF3PSEnqVBTncndsS4Z58QoY9An135DwQiiXS 'test token' TEST https://stablecoin.z.com/.well-known/zusd.json Signature: 9sKCsT4dA4n3C7rcZvVwujFFAdeXZWjuL5AD6gf7xSEpkH7ASHsZr1qH66hXEbWwgxNduiyPJGbFkXL3r45fdCp ーーーーーーーーーーーー solana account suDf4QQF3PSEnqVBTncndsS4Z58QoY9An135DwQiiXS Public Key: suDf4QQF3PSEnqVBTncndsS4Z58QoY9An135DwQiiXS Balance: 0.00352176 SOL Owner: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb Executable: false Rent Epoch: 18446744073709551615 Length: 378 (0x17a) bytes 0000: 01 00 00 00 9d 45 cf 13 6b ae f1 9b 87 31 a6 ef .....E..k....1.. 0010: 2d e5 6b 22 21 7e 92 ed 43 f3 7b 4f 9d 75 65 0e -.k"!~..C.{O.ue. 0020: 2f 12 a3 ac 00 00 00 00 00 00 00 00 09 01 00 00 /............... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00a0: 00 00 00 00 00 01 12 00 40 00 9d 45 cf 13 6b ae [email protected]. 00b0: f1 9b 87 31 a6 ef 2d e5 6b 22 21 7e 92 ed 43 f3 ...1..-.k"!~..C. 00c0: 7b 4f 9d 75 65 0e 2f 12 a3 ac 0d 0a 15 72 16 d5 {O.ue./......r.. 00d0: b8 ea 9f 3f 1a 5c 98 90 dd 37 ab 41 f9 ba 97 b8 ...?.\...7.A.... 00e0: 1a 75 d7 ce 71 ab ca 71 e1 41 13 00 8c 00 9d 45 .u..q..q.A.....E 00f0: cf 13 6b ae f1 9b 87 31 a6 ef 2d e5 6b 22 21 7e ..k....1..-.k"!~ 0100: 92 ed 43 f3 7b 4f 9d 75 65 0e 2f 12 a3 ac 0d 0a ..C.{O.ue./..... 0110: 15 72 16 d5 b8 ea 9f 3f 1a 5c 98 90 dd 37 ab 41 .r.....?.\...7.A 0120: f9 ba 97 b8 1a 75 d7 ce 71 ab ca 71 e1 41 0a 00 .....u..q..q.A.. 0130: 00 00 74 65 73 74 20 74 6f 6b 65 6e 04 00 00 00 ..test token.... 0140: 54 45 53 54 2e 00 00 00 68 74 74 70 73 3a 2f 2f TEST....https:// 0150: 73 74 61 62 6c 65 63 6f 69 6e 2e 7a 2e 63 6f 6d stablecoin.z.com 0160: 2f 2e 77 65 6c 6c 2d 6b 6e 6f 77 6e 2f 7a 75 73 /.well-known/zus 0170: 64 2e 6a 73 6f 6e 00 00 00 00 d.json....
solscanからすると、InitializeMetadataPointerというインストラクションで、MetadataAddressはミントアカウントのアカウントにしました。ここでのAuthorityとは、Authorityのアカウントは後ほどMetadataAddressを変更する権限の持つアカウントです。
3.1.2. Metaplexでメタデータを付ける
ts-node set_metadata_for_spl_token_2022.ts suDf4QQF3PSEnqVBTncndsS4Z58QoY9An135DwQiiXS set metadata for spl-token-2022! /Users/usr0102794/gyen2022/video-tutorial-resources/metadataUpdate/node_modules/@solana/web3.js/src/connection.ts:5922 throw new SendTransactionError( ^ Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: custom program error: 0xc4 at Connection.sendEncodedTransaction (/Users/usr0102794/gyen2022/video-tutorial-resources/metadataUpdate/node_modules/@solana/web3.js/src/connection.ts:5922:13) at processTicksAndRejections (node:internal/process/task_queues:95:5) at Connection.sendRawTransaction (/Users/usr0102794/gyen2022/video-tutorial-resources/metadataUpdate/node_modules/@solana/web3.js/src/connection.ts:5881:20) at Object.sendTransaction (/Users/usr0102794/gyen2022/video-tutorial-resources/metadataUpdate/node_modules/@metaplex-foundation/umi-rpc-web3js/src/createWeb3JsRpc.ts:327:25) at TransactionBuilder.sendAndConfirm (/Users/usr0102794/gyen2022/video-tutorial-resources/metadataUpdate/node_modules/@metaplex-foundation/umi/src/TransactionBuilder.ts:359:23) at main (/Users/usr0102794/gyen2022/video-tutorial-resources/metadataUpdate/set_metadata_for_spl_token_2022.ts:67:18)
「0xc4」というエラーとなってしまいました。
TokenMetadataの拡張でメタデータを付けたアカウントにはMetaplexで再びメタデータを付けることができないという結論です。
3.1.3. Metaplexのメタデータプログラムの0xc4エラーについて
ここからすると、「Invalid metadata pointer」というエラーです。どのようなケースで、metadata pointerが無効化、コードを追ってみました。ここからすると、Metadata pointer extensionのauthority は Noneではない、または、metadata_addressはMetaplexメタデータプログラムのPDAではない場合、このようなエラーとなりますね。
つまり、Metaplexメタデータプログラムを通して、メタデータを付ける場合、metadata_addressはミントアカウントのアドレスと同じにすることができません。そして、authority は Noneに初期化されることで、これからmetadata_addressの変更もさせません。
これで、MetaplexとTokenMetadataの拡張が同時に備えることが不可能させます。素晴らしい案ですね。
3.1.4. Metaplexでメタデータを付けるために、MetadataPointer拡張でauthorityをnoneに、metadataAddressをMetaplexメタデータプログラムのPDAに、しなければならない
create_mint.ts.tsimport * as token from "@solana/spl-token"; import * as web3 from "@solana/web3.js"; import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'; import { findMetadataPda} from "@metaplex-foundation/mpl-token-metadata"; import { fromWeb3JsPublicKey} from '@metaplex-foundation/umi-web3js-adapters'; const SPL_TOKEN_2022_PROGRAM_ID = new web3.PublicKey( 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' ); const provider = "https://api.devnet.solana.com"; const connection = new web3.Connection(provider); export function loadWalletKey(keypairFile:string): web3.Keypair { const fs = require("fs"); const loaded = web3.Keypair.fromSecretKey( new Uint8Array(JSON.parse(fs.readFileSync(keypairFile).toString())), ); return loaded; } async function main(){ console.log("create spl-token-20222 tokens with metadata extension"); const myKeypair = loadWalletKey("id.json"); const destinationKeypair = web3.Keypair.generate(); const destination = destinationKeypair.publicKey; console.log("mint account address is : ", destination.toString()); const accountLen = token.getAccountLen([token.ExtensionType.PermanentDelegate, token.ExtensionType.DefaultAccountState, token.ExtensionType.MetadataPointer]); const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); const transaction = new web3.Transaction().add( web3.SystemProgram.createAccount({ fromPubkey: myKeypair.publicKey, newAccountPubkey: destination, space: accountLen, lamports, programId: SPL_TOKEN_2022_PROGRAM_ID, }), token.createInitializePermanentDelegateInstruction(destination, myKeypair.publicKey, SPL_TOKEN_2022_PROGRAM_ID), token.createInitializeDefaultAccountStateInstruction(destination, token.AccountState.Initialized, SPL_TOKEN_2022_PROGRAM_ID), ); const authority = process.argv[2]; if(process.argv.length < 4){ const umi = createUmi("https://api.devnet.solana.com"); const metaaddress = findMetadataPda(umi,{mint: fromWeb3JsPublicKey(destination)}) const tmp = metaaddress.toString().split(","); console.log("metadata address is : ", tmp[0]); transaction.add( token.createInitializeMetadataPointerInstruction(destination, authority == 'null'? null:new web3.PublicKey(authority), new web3.PublicKey(tmp[0]), SPL_TOKEN_2022_PROGRAM_ID) ); }else{ transaction.add( token.createInitializeMetadataPointerInstruction(destination, authority == 'null'? null:new web3.PublicKey(authority), destination, SPL_TOKEN_2022_PROGRAM_ID) ); } transaction.add( token.createInitializeMintInstruction(destination, 6, myKeypair.publicKey, myKeypair.publicKey, SPL_TOKEN_2022_PROGRAM_ID) ); const transactionSignature = await web3.sendAndConfirmTransaction(connection, transaction, [myKeypair, destinationKeypair]); console.log("transactionSignature: ", transactionSignature); } main();
ミントアカウントを作成する。
ts-node create_mint.ts null create spl-token-20222 tokens with metadata extension mint account address is : 5ytCPtnht5KzbmmssdGy2xLKEVnY8bQQ5NYeQRSaHn5a metadata address is : DSheKJoBbEF3wEdfKReSmprLJaETPhhWRkcHbgiukbCR transactionSignature: 2Ve5GTBnwE3XZa3FfivbsmCvmcLsBRiRugDQNivWzYWgJZg4zJLSbJZodzU4hZr7rgCu8kLDgCi5B3WECbkDgVe5
Metaplexでメタデータを付ける。
ts-node set_metadata_for_spl_token_2022.ts 5ytCPtnht5KzbmmssdGy2xLKEVnY8bQQ5NYeQRSaHn5a set metadata for spl-token-2022! set metadata success! 3LyhqsXywyqHbN3hEXd5d1BmFpanEgbXyw5sK1FvdT9xsVagKb4JjfoaNgyhwVzDNmfHj37RB9D9c33LYTRvVwtu
4.まとめ
Solanaでの既存のToken Programのトークンには、メタデータの付けは依然としてMetaplexに頼るしかないですが、Token-2022プログラムのトークンに対しては、メタデータの付け方の選択肢が増えます。metadata_addressをミントアカウントアドレスと同じにして、metadataをミントアカウントに記入する案は、将来はより多く採用されるかと予想しています。重要なのは、TokenMetadataの拡張とMetaplexの両方が同時に備えられないことです。これで、トークンには正当なメタデータは永遠に一つしかないことが保証されます。
2024年、SolanaのToken-2022プログラムの大活躍に一緒に期待しましょう。
5.最後に
次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ募集職種一覧からご応募をお願いします。皆さんのご応募をお待ちしています。