Solana Developer Hub #3: 解説Token Extensions
この記事は2023/2/22に開催したSolana Developer Hub Online #3で話をした「解説: Token Extensions」を再編集したものになります。
解説: Token Extensions
私はトークン大好きおじさんです。このToken Extensionsのために改めてトークンを触って、やはりトークンはよくできていて良いです。
このToken Extensionsは2024/01/24に発表のあったトークンの拡張機能です。元々はToken-2022という名前で開発されており、Token Extensionsはそれによってできることになった総称になります。
そのため、技術的なところを調べたい場合はToken-2022で検索してもらった方が具体的な話を見つけやすくなります。
Token Extensionsの登場によってToken Programがパワーアップしました。実際に何ができるようになったのか見ていきましょう。
と行く前に、まず用語の認識合わせをしましょう。
このToken Programに出てくる用語として
(Mint) Token
Solanaチェーン上で1つだけ存在してトークンの供給量などを管理するアカウント
(Associated) Token Account
Solanaチェーン上で複数存在してユーザー(ウォレット)がどれだけトークンを所有しているか管理するアカウント
というものがあります。この2つの用語はSolanaではどちらもAccountと呼ばれるものになります。
本記事では前者をToken、後者をATAと表記して区別します。
Token Extensions概要
Token Extensionsでは全13機能がToken Programに入りました。
従来のToken Programのアドレスと、Token-2022 Program (Token ExtensionsのProgram)はアドレスが変わります。Solana CLIなどでは自動でProgramアドレスが変わりますが、自身のプログラムなどで利用するさいには変更が必要になるので気をつけてください。
それぞれの機能
今回の説明ではspl-tokenというCLIツールを利用しています。
spl-tokenではなく@solana/web3.jsやsolana-sdk、curlなど、Solanaチェーンにトランザクションを送信できれば同様のことはできるので、適時読み替えてください。
Mint Close Authority
Mint Close Authorityでは作成したTokenを削除できるようになりました。
従来のToken ProgramではTokenを削除することができませんでしたが、Mint Close AuthorityでTokenを削除することでrent(Accountを保持するための保管しているlamports)を取り戻せるようになりました。
ただし、Tokenを削除できるのは供給量が0のときだけのため、Mainnetなどでトークンを配布したさいにはトークンを全て焼却するまで削除できなくなります。
Mint Close Authorityのユースケースとしては、実験的にトークンを発行してみたなどの開発中のフェーズでrentの回収をするといったあたりが考えられます。
Mint Close Authorityを有効にしてTokenを作成するとSolana Explorer上でClose Authorityという項目が追加されます。こちらに記載されたアドレスの所有者のみがTokenを削除することができます。
Transfer Fees
Transfer Feesではトークンの転送時にfeeを設定できるようになりました。
従来ではATAを凍結しておいて、転送時に凍結を解除して、転送後に再度凍結することでfeeの支払いを強制することができました。しかし、この方法は実装の手間があり、また完全にfeeの支払いを強制することが難しさがありました。(と、ドキュメント上には完全性がないという記載がありました)
Transfer Feesのユースケースとしては、NFTの売買時に発行者に渡すfeeを強制するなどが考えられます。
Transfer Feesを有効にしてTokenを作成すると、Solana Explorer上でTransfer Fee Configという項目が追加されます。
注意点として、このTransfer Feesで徴収するfeeは自動的に特定のATAに転送される訳ではありません。このfeeは転送先のATAに保持され、引き出しは専用のInstructionを使って行います。
Solana Explorer上でATAを参照すると現在の徴収可能額を確認できます。
そのため、Transfer Feesによってfeeを徴収しやすくなった代わりに、Tokenの提供者は各ATAからfeeを回収する仕組みを作る必要がでてきます。
Non-Transferable
Non-Transferableではトークンの転送を禁止できるようになりました。
従来の凍結でも同様のことはできましたが、凍結と違い焼却は可能という点に違いがあります。
この機能を有効にして実際に送信すると、Programとしては失敗し、ログに Transfer is disabled for this mint というログが出るようになります。
Non-Transferableのユースケースとしては、証明書としてATAに転送不可のトークンをmintして、そのトークンの保有者にしかできない何かを提供するなどが考えられます。わかりやすい例としてはスマホのSolana Mobileの購入者にトークンを発行して、トークン所有者にエアドロするなどですね。
Non-Transferableを有効にするとSolana Explorer上にはNon-Transferableという項目が追加されます。
注意点としてTokenの発行者も転送できないので注意してください。
他者に対して発行したい場合は、トークンをmintするさいに付与するATAのアドレスを指定してください。ただし、相手はそのトークンのATAを保有している必要があるため、ATAも合わせて作成するようにトランザクションを作らなければなりません。
Interest-Bearing Tokens
Interest-Bearing Tokensではトークンに金利を設定して、金利付きの金額を取得できるようになりました。
金利はネットワークのタイムスタンプに基づいて複利計算され、Tokenを作成してからの経過時間で金利が計算されます。ただし、注意点としてこの金利は見かけ上の金利であり、実際にその金利分のトークンがmintされている訳ではありません。
Interest-Bearing Tokensは私も理解できておらず、具体的なユースケースは見えていません。もし、ユースケースがわかる方がいらっしゃれば @k-kinzal までご連絡ください。
Interest-Bearing Tokensを有効にするとSolana Explorer上ではInterest-Bearingという項目が追加されます。
Permanent Delegate
Permanent Delegateで各ATAでの転送、焼却の操作を委譲できるようになりました。
わかりやすいユースケースとしては、ハッキングなどでトークンが流出してしまったさいに元の持ち主に強制的な返却、または焼却で利用できないようにするなどが考えられます。
ただし、注意点としてこれはとても強い権限の委譲になります。例えば悪意あるユーザーに委譲された場合には全ユーザーが持つトークンの回収、焼却といったことができてしまいます。
また、これは検証して気になった点ですが、一度委譲を行うと委譲先のアカウントからしか操作できず、発行者からこの委譲した権限の剥奪する方法を見つけることはできませんでした。
そのため、Permanent Delegateを利用するさいには慎重な設計を求められます。これは推測になりますが、この機能は人ではなくProgramに委譲することが望ましいと思われます。
Permanent Delegateを有効にするとSolana Explorer上ではPermanent Delegateという項目が追加されます。ここで指定されたアドレスが委譲された操作をできます。
Transfer Hook
Transfer Hookではトークンを転送したさいに特定のプログラムを呼び出せるようになりました。
ユースケースとしては、NFTで所有者の移転のさいのロイヤリティの徴収や、DAOで承認があったさいのみトークンの転送を許可するなどが考えられます。
Transfer Hookを行うProgramの作成方法は通常のProgramと同様です。ただし、Instructionsが専用のものになります。
Execute
トークン転送時に実行されるInstructionはこのExecuteになる
InitializeExtraAccountMetaList
UpdateExtraAccountMetaList
InitializeExtraAccountMetaList/UpdateExtraAccountMetaListに関してはまだ未調査で、どのタイミングで発行されるものかは把握できていません。
Transfer Hookの詳細に関してはこちらを参照ください。
Metadata
MetadataではTokenに対してメタデータを付与できるようになりました。
トークン名
シンボル
URL
追加情報
キーとバリューのペア
ユースケースとしてはさまざまですが、NFTのメタデータ管理などで使うというのはわかりやすいケースです。
Metadataを有効にするとSolana Explorer上でMetadataという項目が追加されます。
Metadata Pointer
Metadata Pointerは先ほど紹介したMetadataで設定したメタデータを参照するように設定できるようになりました。
メタデータとしては共通だが違うトークンをmintするさいに、同じメタデータを扱っていることを表したり、Accountサイズを減らしてrentの節約をすることができます。
Metadata Pointerを有効にするとSolana Explorer上ではMetadataという項目が追加されます。Metadataと違い、参照先のアドレスが設定されます。
Confidential Transfers
Confidential Transfersは転送する金額や残高などトランザクション上で非表示になり、プライバシーを向上させることができます。
ただし、この機能は2024/02時点ではまだ有効になっていません。現時点では有効にしようとするとエラーが出ることに注意してください。
Immutable Owner
Immutable OwnerでATAのオーナーは変更できないようになりました。
従来のToken ProgramではATAのオーナーを変更できましたが、Token-2022 Programではデフォルトで変更不可になり、より安全な形になりました。
Immutable Ownerを有効にするとSolana Explorer上ではImmutable Ownerという項目が追加されます。
Required Memo on Transfer
Required Memo on Transferではトークンを受信する側のATAで転送時にメモを追加することを強制できるようになりました。
ドキュメントによると、銀行間の取引などではメモを付けることが必須であり、そのユースケースを満たすための機能になるようです。
ただし、メモの内容に関しては書式などの制限はできないため内容を制限したい場合はTransfer Hookで別途制限を加えてください。
Required Memo on Transferを有効にするとSolana Explorer上でRequire Memo on Incoming Transfersという項目が追加されます。
CPI Guard
CPI GuardではATAに対してのCPIで特定の操作を禁止できるようになりました。
CPIはCross Program Invocationの略で、SolanaのProgramから他のProgramを呼び出すことで、Programの実装をシンプルに保てるという便利な機能になります。
しかし、ユーザー視点で見るとCPIには難しさがあり、図のようにClientから1つめのProgramに渡すトランザクションはユーザーから確認可能です。しかし、CPIで呼び出される2つめのOther Programのトランザクションは確認ができないという問題があります。
そこで悪意あるProgramで実行されても安全にできるように、ATAの特定の操作をCPIから実行できないように禁止する機能がCPI Guardになります。
ただし、CPI自体は基本的な機能であり、これを有効にすることでセキュリティが向上する代わりに、一部のProgramが動作しなくなるという利便性とのトレードオフが発生する可能性がでてきます。
CPI Guardを有効にするとSolana Explorer上にCPI Guardという項目が追加されます。
Default Account State
Default Account StateでATAの作成時にデフォルトの状態を指定できるようになりました。
ATAのデフォルト状態としてはinitialized、frozenの2つの状態を指定することが可能です。
注意点
Token Extensionを使う上で、組み合わせによっては意味がない組み合わせがあることに注意してください。
例えばNon-TransferableとTransfer Hookの組み合わせは、転送できないのにHookを設定するという意味がない組み合わせになります。
余分な設定をするとAccountの容量が増え、rentに必要なlamportsの量が増えてしまうので気をつけましょう。
まとめ
Token Extension楽しい!
https://solana.com/ja/developers/guides?tags=token+extensions&tags=token+2022
https://www.youtube.com/playlist?list=PLilwLeBwGuK6imBuGLSLmzMEyj6yVHGDO
https://www.youtube.com/watch?v=CEuKahqOYbs&list=PLilwLeBwGuK7MVdX1GbZwUeALfNCXWH_8