1週間前、私のSolanaトークンはただのランダムな文字列でした。名前もルールも個性もありませんでした。この1週間で、手数料を自動徴収するトークン、一切移動できないトークン、そして仕事と好意を同時に行うトークンを作ることができました。Token Extensionsで構築して学んだことを、Web2プラットフォームでは決して得られなかった視点からお伝えします。

スタート地点

Web2のバックグラウンドを持つ私にとって、「トークン」のメンタルモデルは基本的に、残高列を持つデータベースの1行でした。トークンに名前を付けたければ、別のテーブルと結合すればよかったのです。トランザクション手数料を課したければ、データベースに到達する前に転送リクエストをインターセプトするミドルウェアを書けばよかったのです。再販できないものにしたければ、アプリケーションコードにif文を書き、すべてのクライアントがそれを尊重してくれることを祈ればよかったのです。

SolanaのToken Extensions Programは、このモデル全体を投げ捨ててくれます。mintはアカウントに直接名前とシンボルを持たせることができます。カスタムバックエンドコードを1行も書かずに、すべての転送に手数料を強制することができます。全く移動を拒否することもでき、その拒否は私が書いたコードではなく、プログラムの中で起こります。手作業で構築していたすべてのルールが、すでにフラグとして存在していたのです。

ウォークスルー

トークンにアイデンティティを与える

私の最初の本物のmintには名前が全くありませんでした。ただのアドレス、GscCeGeQhmN92SLaXAHoWee78KKb5PBkTrkMiYdy2Nc8で、エクスプローラーで見ると、列ヘッダーのないスプレッドシートを開いたような感覚でした。メタデータを追加することで、1つのコマンドで修正できました:

spl-token create-token \
  --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
  --enable-metadata \
  --decimals 9

spl-token initialize-metadata GscCeGeQhmN92SLaXAHoWee78KKb5PBkTrkMiYdy2Nc8 \
  "ReinforceCoin" "RFC" \
  "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/CompressedCoil/metadata.json"

Enter fullscreen mode Exit fullscreen mode

Web2の観点では、これはユーザーがポイントを獲得する前に、ポイントプログラムの表示名とアイコンを定義するのと同等です。ただし、ここでは名前は残高ロジックと同じアカウントに存在します。同期を保つ必要のある別個のメタデータサービスはありません。

プロトコルに手数料を自動徴収させる

次に、作成時に転送手数料が組み込まれたmintを作成しました。BzJPUdX7kfiXzowvXwNMQgpqCbae5XwbDRWxp92mwAgs、1パーセントに設定:

spl-token create-token \
  --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
  --transfer-fee-basis-points 100 \
  --transfer-fee-maximum-fee 5000

Enter fullscreen mode Exit fullscreen mode

100トークンを2番目のウォレットに送信すると、100を受け取ると思っていました。99を受け取りました。欠けていたトークンは失われたのではなく、受取人自身のアカウントに直接差し引かれ、彼らには触れられず、引き出し権限者が引き出すのを待っていました:

spl-token withdraw-withheld-tokens CftRHxRFNNwKS5LbTZ6L6sqVtQ57LbmfDqEuKHzmWLxs \
  4x3o6cotxU4fqrPtetdTmKgGkMK86pb4FfZm93i1TUJt

Enter fullscreen mode Exit fullscreen mode

私の残高は900から901になりました。決済プロセッサも、Webhookも、照合ジョブもありません。手数料徴収はmint自体のプロパティでした。

1つのmintに両方を積み重ねる

各拡張機能を個別に理解した後、単一のmint、9LqGwgZKcjBJ3ccUv4uftRWoNdKAive2u4fueonCKNAに組み合わせました。ReinforceCoinという名前で、メタデータと2パーセントの転送手数料を同時に持ちます。100トークンの転送で、受取人の支出可能残高に98が残り、2が差し引き状態にあり、以前と同じメカニズムが、手数料と名前とシンボルが同時に動作する形で実行されました。メタデータを追加しても手数料の動作は変わらず、手数料を追加してもメタデータの表示は変わりませんでした。

移動を拒否するものを作る

今週で最も興味深かったmintは、最もシンプルなコマンドでした。1つのフラグ、--enable-non-transferableを追加することで、プロトコルが誰も移動させないトークンが生成されました:

spl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb --enable-non-transferable

Enter fullscreen mode Exit fullscreen mode

これらのトークンを10個ミントし、意図的に2番目のウォレットに送信しようとして失敗する様子を確認しました。拒否はプログラムから直接来ました:

Program log: Instruction: TransferChecked
Program log: Transfer is disabled for this mint
Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb failed: custom program error: 0x25

Enter fullscreen mode Exit fullscreen mode

これがルールと提案の違いです。Web2では、「この資格情報は譲渡できません」は利用規約の1行か、せいぜいAPIのチェックです。ここでは、重力が強制されるのと同じ方法で強制されます。誰も書くことのできないクライアントが回避できる方法はありません。なぜなら、拒否はアプリケーショコードではなく、トークンプログラムの中で起こるからです。

驚いたこと

non-transferableはトークンが完全に凍結され、あらゆる意味で永続的であることを意味すると予想していました。しかし、そうではありません。バーンは完全に機能します:

spl-token burn 2joYCLK6QTfQ1FwsKijU7dMn2CDM8r6YZ3asoVxGL61j 3 \
  --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb

Enter fullscreen mode Exit fullscreen mode

私の残高は10から7に減少し、エラーも抵抗もありませんでした。その区別は私にとって即座に理解できました。non-transferableは所有者がトークンの制御を失うことを意味するのではなく、トークンが所有者を変更する能力を失うことを意味します。所有者はまだ自分が持っているものを破壊することができます。ただ、それを他の誰かに渡すことはできないのです。この単一の詳細が、soulboundパターンを実際に資格情報や修了証明書などの用途に有用にするものです。所有者が自分の資産に対する権限を保持しつつ、売却や取引をできないようにしたい場合に有用です。

次にすること

今週のすべての拡張機能は、独自のmintに存在するか、1つの他のものとペアになっていました。次はさらに進んで、アカウントサイズとレントコストが重要になり始める前に、単一のトークンにどれだけ現実的に積み重ねることができるか、そして実際のアプリケーションがCLIに依存せずにオンチェーン設定を読み取る方法を調べ始めたいと思います。

この投稿は#100DaysOfSolanaの一部です。フォローするか、いつでも参加してください。