導入
「独自のトークンを発行する」と聞くと難しそうですが、Solanaではすでに存在する共通のプログラム(Token Program)を使うだけで実現できます。ポイントは、トークンの情報が「発行元の情報」と「持ち主ごとの残高」という2種類の別々のアカウントに分かれていることです。
説明
SPL Tokenでは、1つのトークンの種類ごとに Mint(ミント) アカウントが1つ存在します。Mintは「このトークンの名前は何か」ではなく、供給量・小数点以下の桁数(decimals)・誰が新規発行できるか(mint authority)といったトークン全体のメタ情報を持つアカウントです。
一方、あるユーザーがそのトークンをいくら持っているかは、Mintの中には保存されません。ユーザーごとに Token Account(トークンアカウント) という別のアカウントが作られ、そこに「どのMintの」「誰の持ち物として」「いくら」保有しているかが記録されます。
graph TB
M["Mintアカウント<br/>(supply, decimals, mint authority)"]
TA1["Token Account 1<br/>owner: ウォレットA<br/>amount: 100"]
TA2["Token Account 2<br/>owner: ウォレットB<br/>amount: 50"]
TA3["Token Account 3<br/>owner: ウォレットC<br/>amount: 0"]
M -. このMintの残高を表す .-> TA1
M -. このMintの残高を表す .-> TA2
M -. このMintの残高を表す .-> TA3
この設計は、Ethereum の ERC-20(Solidityコースで扱う代表的なトークン規格)とは考え方が異なります。ERC-20は「1つのコントラクトが、全ユーザーの残高を1つの mapping としてまとめて持つ」のに対し、SPLトークンは「残高そのものが独立したアカウントとして、ユーザーごとに存在する」という違いがあります。
| SPL Token(Solana) | ERC-20(Ethereum) | |
|---|---|---|
| 残高の保存場所 | ユーザーごとの独立したToken Account | トークンコントラクト内のmapping(address => uint256) |
| 残高を読む方法 | 該当のToken Accountを直接読む | コントラクトにbalanceOfを問い合わせる |
| 発行元の情報 | Mintアカウント | コントラクト自身 |
Solanaが「アカウントモデル」(第2章)を採用していることが、ここにも表れています。データが常に独立したアカウントに分かれ、Token Programはそれらのアカウントを読み書きするロジックだけを提供する、という関係です。
演習
あるユーザーが5種類のトークンを保有しているとき、そのユーザーに関連するToken Accountはいくつ存在するでしょうか。Mintとの関係を思い出して考えてみましょう。
ヒント1を見る
Token Accountは「(ユーザー, Mint)の組み合わせ」ごとに1つです。
ヒント2を見る
5種類のMintそれぞれについて、そのユーザー用のToken Accountが1つずつ必要になります。