紹介
はじめに
Last updated August 27, 2026
このガイドは、MPL-Distro と Umi フレームワーク で既存トークンを 2 つのウォレットへ送ります。
概要
MPL-Distro のローンチには、既存の SPL トークン mint、保存済みのオフチェーン Merkle 割り当て、配布ボールト内の十分なトークンが必要です。
prepareDistributionでルートと証明を構築します。- 7 日間の
Wallet配布を permissionless 送信で作成します。 - クレーム開始前にすべての割り当ての合計を入金します。
- ツリーにコミットした exact な amount、nonce、証明を送信します。
構築するもの
2 人の受取人の配布を作成し、350,000 トークン最小単位を入金し、最初の受取人の 100,000 単位クレームを送信します。
CLI から作成と資金投入
Metaplex CLI で配布の作成とトークンの入金・出金ができます。Merkle 証明の生成とクレーム送信はこの SDK ウォークスルーで行います。
ジャンプ先: 前提条件 · インストール · 作成 · 資金投入 · クレーム · エラー
クイックスタート
MPL-Distro のクイックスタートには 4 つの必須フェーズがあります。
- MPL-Distro クライアントをインストールし、Umi に
mplDistro()を登録します。 - 割り当てのルート、証明、amount、nonce を生成して保存します。
- 配布を作成し、トークン割り当て全体を入金します。
distributeで証明を送信し、クレームレシートを検証します。
前提条件
MPL-Distro には資金のある Solana 署名者と、オリジナル SPL Token プログラム所有の既存 mint が必要です。
- Node.js 20 以降
- 家賃、トランザクション手数料、0.002 SOL クレームプロトコル手数料用の SOL を持つ Umi identity
- 既存の SPL トークン mint と、その権限者の資金のある associated token account
- トークン最小単位で表した受取人アドレスと割り当て量(mint の最小単位。decimals が 6 のトークンは 1.0 トークンあたり
1_000_000単位)
この例は Token-2022 mint を受け付けません。オリジナル SPL Token プログラム mint を使ってください。
MPL-Distro SDK のインストール
トランザクションを準備して送信するアプリケーションに、MPL-Distro クライアントとその Umi ピア依存をインストールします。
npm install @metaplex-foundation/mpl-distro@^0.4 \
@metaplex-foundation/umi@^1.1 \
@metaplex-foundation/umi-bundle-defaults \
@metaplex-foundation/mpl-toolbox@^0.10
Core アセットサイナーへクレームする場合のみ @metaplex-foundation/mpl-core をインストールします。
ウォレット配布の作成
受取人リストを Merkle ルートとしてコミットし、返された証明をオフチェーンに保存して配布を作成します。
1import {
2 AllowedDistributor,
3 createDistribution,
4 DistributionType,
5 findDistributionPda,
6 mplDistro,
7 prepareDistribution,
8} from '@metaplex-foundation/mpl-distro'
9import { generateSigner, publicKey } from '@metaplex-foundation/umi'
10import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
11
12const umi = createUmi(
13 process.env.RPC_URL ?? 'https://api.devnet.solana.com'
14).use(mplDistro())
15
16// Use umi.use(keypairIdentity(yourKeypair)) when the Umi identity
17// should be the distribution authority.
18
19const mint = publicKey(process.env.TOKEN_MINT!)
20const recipients = [
21 { address: publicKey(process.env.RECIPIENT_1!), amount: 100_000n },
22 { address: publicKey(process.env.RECIPIENT_2!), amount: 250_000n },
23]
24const { root, proofs, treeHeight } = prepareDistribution(recipients)
25const seed = generateSigner(umi)
26const now = BigInt(Math.floor(Date.now() / 1000))
27
28await createDistribution(umi, {
29 mint,
30 seed,
31 merkleRoot: root,
32 treeHeight,
33 startTime: now,
34 endTime: now + 7n * 24n * 60n * 60n,
35 totalClaimants: BigInt(recipients.length),
36 name: 'Community distribution',
37 distributionType: DistributionType.Wallet,
38 allowedDistributor: AllowedDistributor.Permissionless,
39 subsidizeReceipts: false,
40}).sendAndConfirm(umi)
41
42const [distribution] = findDistributionPda(umi, {
43 mint,
44 seed: seed.publicKey,
45})
46
47// Store each recipient's amount, nonce, and proof in your claim service.
48console.log('Distribution:', distribution)
49console.log('Proofs:', proofs)
50
51// Distribution: <distribution PDA>
52// Proofs: <one proof array per recipient>
seed 署名者は mint に対して配布アドレスを一意にするので、同じトークンに複数の配布を持てます。結果の PDA は ["distribution", mint, seed] を使うため、アドレスを再導出する場合は seed 公開鍵を保持する必要があります。
クレーム中は割り当てデータが不変
権限者は startTime <= now <= endTime の間、Merkle ルート、ツリー高、開始時刻、claimant 数を変更できません。クレームを開く前に割り当てファイル全体を検証してバックアップしてください。
ウォレット配布への資金投入
すべての割り当ての合計以上を、プログラム所有の associated token account へ入金して配布に資金を入れます。現在の配布権限者が deposit に署名する必要があります。
1import {
2 deposit,
3 mplDistro,
4} from '@metaplex-foundation/mpl-distro'
5import { publicKey } from '@metaplex-foundation/umi'
6import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
7
8const umi = createUmi(
9 process.env.RPC_URL ?? 'https://api.devnet.solana.com'
10).use(mplDistro())
11
12// The Umi identity must be the current distribution authority.
13
14const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
15const mint = publicKey(process.env.TOKEN_MINT!)
16const totalAmount = 350_000n
17
18await deposit(umi, {
19 distribution,
20 mint,
21 amount: totalAmount,
22}).sendAndConfirm(umi)
23
24// The distribution ATA contains 350000 base units.
このチュートリアルはトークンのみ入金します。任意のクレームレシート家賃補助金は 資金投入と回収 で扱います。
ウォレット割り当てのクレーム
コミット済みリストから生成した同じ受取人、amount、nonce、証明を送信して割り当てをクレームします。
1import {
2 distribute,
3 mplDistro,
4 prepareDistribution,
5} from '@metaplex-foundation/mpl-distro'
6import { publicKey } from '@metaplex-foundation/umi'
7import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
8
9const umi = createUmi(
10 process.env.RPC_URL ?? 'https://api.devnet.solana.com'
11).use(mplDistro())
12
13// The payer may be the recipient or a third-party distributor, depending on
14// the distribution's allowedDistributor setting.
15
16const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
17const mint = publicKey(process.env.TOKEN_MINT!)
18const recipients = [
19 { address: publicKey(process.env.RECIPIENT_1!), amount: 100_000n },
20 { address: publicKey(process.env.RECIPIENT_2!), amount: 250_000n },
21]
22const recipientIndex = 0
23const { proofs } = prepareDistribution(recipients)
24
25await distribute(umi, {
26 distribution,
27 mint,
28 recipient: recipients[recipientIndex].address,
29 amount: recipients[recipientIndex].amount,
30 proof: proofs[recipientIndex],
31 nonce: 0,
32}).sendAndConfirm(umi)
33
34// The recipient ATA receives 100000 base units and a claim receipt is created.
プログラムは必要に応じて受取人の正規 associated token account を作成し、ボールトからトークンを転送し、クレームレシートを作成します。同じ割り当ての 2 回目のトランザクションは AlreadyClaimed で失敗します。
MPL-Distro アカウントの検証
確認後に配布と決定的クレームレシートを取得してクレームを検証します。
1import {
2 fetchClaimReceipt,
3 fetchDistribution,
4 findClaimReceiptPda,
5 mplDistro,
6} from '@metaplex-foundation/mpl-distro'
7import { publicKey } from '@metaplex-foundation/umi'
8import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
9
10const umi = createUmi(
11 process.env.RPC_URL ?? 'https://api.devnet.solana.com'
12).use(mplDistro())
13
14const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
15const recipients = [
16 { address: publicKey(process.env.RECIPIENT_1!), amount: 100_000n },
17 { address: publicKey(process.env.RECIPIENT_2!), amount: 250_000n },
18]
19const recipientIndex = 0
20
21const [receipt] = findClaimReceiptPda(umi, {
22 distribution,
23 recipient: recipients[recipientIndex].address,
24 amount: recipients[recipientIndex].amount,
25 nonce: 0,
26})
27
28const [distributionAccount, receiptAccount] = await Promise.all([
29 fetchDistribution(umi, distribution),
30 fetchClaimReceipt(umi, receipt),
31])
32
33console.log(distributionAccount.claimCount)
34console.log(receiptAccount.amount)
35
36// claimCount includes this allocation and the receipt stores 100000
よくある MPL-Distro エラー
MPL-Distro エラーは、一致しない証明、期間、権限、ボールト残高を示します。
| エラー | 原因 | 対処 |
|---|---|---|
InvalidClaimProof | アドレス、amount、nonce、または証明がコミット済みリーフと異なる | 同じ保存済み割り当てレコードからすべての値を読み込む |
DistributionNotStarted | クラスタタイムスタンプが startTime より前 | 設定された Unix タイムスタンプまで待つ |
DistributionEnded | クラスタタイムスタンプが endTime より後 | 権限者が新しい配布を作成する必要がある |
AlreadyClaimed | クレームレシート PDA がすでに存在する | 割り当てを完了として扱う |
InsufficientFunds | 記録された配布残高がクレーム量より少ない | アクティブ期間の前・中・後に追加入金するか、以前の出金を確認する |
RecipientMustSign | recipient ゲートのクレームで受取人署名者が欠けている | 受取人を署名者として送信する |
InvalidDistributor | permissioned distributor が一致しない | 設定された distributor 署名者を使う |
検証済み構成
はじめにのフローは、現行の MPL-Distro クライアントテストと生成済み命令ビルダーに基づきます。
| コンポーネント | バージョン |
|---|---|
@metaplex-foundation/mpl-distro | 0.4.x |
@metaplex-foundation/umi | 1.1.x 以降 |
@metaplex-foundation/mpl-toolbox | 0.10.x |
| Token program | オリジナル SPL Token プログラム |
注意事項
はじめにのフローは小さなウォレット配布を示します。本番デリバリー が証明保存、クレームページ、未クレームトークンの回収を扱います。
- Unix タイムスタンプは秒であり、JavaScript のミリ秒ではありません。
- トークン最小単位の数量とタイムスタンプには
bigintを使います。 prepareDistributionは 1,000 割り当てでメモリ最適化実装に切り替わります。- 非常に大きな割り当て構築は制御された Node.js プロセスで実行し、mainnet に資金を入れる前に証明配信をテストしてください。
- Permissionless の支払者は別ウォレットのクレームを送信できますが、トークンはその受取人にだけ届きます。
FAQ
MPL-Distro はトークン mint を作成しますか?
いいえ。配布を作成する前に SPL トークン mint を作成して資金を入れてください。
Merkle 証明はどこに保存すべきですか?
プログラムが保存するのはルートだけなので、各アドレス、amount、nonce、証明を耐久性のあるデータベースまたはクレームファイルに保存してください。本番デリバリー を参照してください。
1 つのウォレットが複数の割り当てを受け取れますか?
はい。それ以外は同一のウォレットと amount の割り当てごとに異なる nonce を割り当てます。
