操作
資金投入と回収
Last updated August 26, 2026
MPL-Distro は、配布ボールトのトークン資金と、クレームレシート家賃用の任意 SOL 資金を分けます。
概要
権限者は SPL トークンを配布の associated token account へ入金し、レシート補助金が有効なときは配布 PDA に SOL を入れることができます。
- すべての Merkle 割り当てをカバーする十分なトークン最小単位を入金します。
- 成功が想定されるクレームごとに 1 回のクレームレシート家賃を予算化します。
- 記録された
totalAmountと実際のボールトトークン残高の両方を監視します。 - 配布が非アクティブなときだけ、未クレームトークンと未使用補助金 SOL を引き出します。
クイックスタート
MPL-Distro の資金投入と回収は 4 つの運用手順に従います。
- すべての割り当て量を合計し、そのトークン最小単位を入金します。
- レシート補助金が有効なときは、想定レシート家賃予算を配布 PDA へ転送します。
- 実際のボールト残高、配布 SOL、クレーム合計を監視します。
- 期間終了後、未クレームトークンと未使用補助金 SOL を引き出します。
配布トークンを入金する
deposit 命令は入金者のアカウントから配布 PDA の正規 associated token account へトークンを転送します。別ウォレットがトークンを供給する場合でも、現在の配布権限者がすべての入金に署名する必要があります。
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.
SDK は depositor、payer、authority を Umi 支払者にデフォルトし、両方の associated token account を導出します。別ウォレットが元トークンを所有するときは別の入金者署名者を渡し、現在の配布権限者も渡します。
1import { deposit, mplDistro } from '@metaplex-foundation/mpl-distro'
2import { publicKey } from '@metaplex-foundation/umi'
3import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
4
5const umi = createUmi(
6 process.env.RPC_URL ?? 'https://api.devnet.solana.com'
7).use(mplDistro())
8
9const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
10const mint = publicKey(process.env.TOKEN_MINT!)
11const amount = 350_000n
12const treasurySigner = umi.identity
13const feePayer = umi.payer
14const distributionAuthority = umi.identity
15
16await deposit(umi, {
17 distribution,
18 mint,
19 depositor: treasurySigner,
20 payer: feePayer,
21 authority: distributionAuthority,
22 amount,
23}).sendAndConfirm(umi)
24
25// Tokens move from the treasury ATA to the distribution vault.
プログラムは各入金後に totalAmount を増やします。Merkle ルートがコミットした割り当ての合計とは比較しません。
トークン入金額を計算する
必要なトークン入金は、mint の最小単位で表したすべての割り当て量の合計です。
1import { publicKey } from '@metaplex-foundation/umi'
2
3const allocations = [
4 { address: publicKey(process.env.RECIPIENT_1!), amount: 100_000n },
5 { address: publicKey(process.env.RECIPIENT_2!), amount: 250_000n },
6]
7
8const totalAmount = allocations.reduce(
9 (total, allocation) => total + BigInt(allocation.amount),
10 0n
11)
12console.log(totalAmount)
13
14// 350000
意図的なバッファを入金するのは、後で余りを回収することを権限者が受け入れるときだけです。記録残高が割り当てより少ないと有効な証明は InsufficientFunds で失敗し、実際のボールト残高が低いと SPL 転送も失敗します。
クレームレシート補助金に資金を入れる
レシート補助金は、各クレームレシート作成に使った家賃を、配布 PDA がトランザクション支払者へ補填できるようにします。
createDistribution 中に subsidizeReceipts を有効にし、RPC で家賃を計算し、SOL を配布 PDA へ直接転送します。
1import { getClaimReceiptSize, mplDistro } from '@metaplex-foundation/mpl-distro'
2import { transferSol } from '@metaplex-foundation/mpl-toolbox'
3import { multiplyAmount, publicKey } from '@metaplex-foundation/umi'
4import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
5
6const umi = createUmi(
7 process.env.RPC_URL ?? 'https://api.devnet.solana.com'
8).use(mplDistro())
9
10const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
11const expectedClaimCount = 2
12
13const receiptRent = await umi.rpc.getRent(getClaimReceiptSize())
14const budget = multiplyAmount(receiptRent, expectedClaimCount)
15
16await transferSol(umi, {
17 destination: distribution,
18 amount: budget,
19}).sendAndConfirm(umi)
20
21// The distribution PDA holds extra SOL for claim-receipt rent.
補助金予算の境界
配布は自身の rent-exempt 最小額を保持する必要があります。残りの SOL が配布家賃と 1 回のレシート補填の両方をカバーできないとき、クレームは InsufficientFundsToSubsidizeReceipts で失敗します。
MPL-Distro 資金投入クイックリファレンス
クレーム費用は固定プロトコル手数料、Solana トランザクション費用、アカウント家賃に分かれます。
| 費用 | デフォルトの支払者 | レシート補助金がカバーするか |
|---|---|---|
| プロトコル手数料(0.002 SOL) | クレームトランザクション支払者 | いいえ |
| トランザクション手数料 | クレームトランザクション支払者 | いいえ |
| クレームレシート家賃 | クレームトランザクション支払者 | はい(有効かつ資金があるとき) |
| 受取人 ATA 家賃 | クレームトランザクション支払者 | いいえ |
未クレームトークンを回収する
配布権限者は、開始時刻の前または終了時刻の後に withdraw で未クレームまたは余りのトークンを回収します。
1import {
2 DISTRIBUTION_SIZE,
3 fetchDistribution,
4 mplDistro,
5 withdraw,
6 withdrawSubsidy,
7} from '@metaplex-foundation/mpl-distro'
8import { publicKey } from '@metaplex-foundation/umi'
9import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
10
11const umi = createUmi(
12 process.env.RPC_URL ?? 'https://api.devnet.solana.com'
13).use(mplDistro())
14
15// The Umi identity must be the current distribution authority.
16
17const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
18const mint = publicKey(process.env.TOKEN_MINT!)
19
20// Token and subsidy withdrawals succeed only outside the active window.
21await withdraw(umi, {
22 distribution,
23 mint,
24 amount: 50_000n,
25}).sendAndConfirm(umi)
26
27const distributionAccount = await fetchDistribution(umi, distribution)
28if (distributionAccount.subsidizeReceipts) {
29 const balance = await umi.rpc.getBalance(distribution)
30 const rent = await umi.rpc.getRent(DISTRIBUTION_SIZE)
31 const unusedSubsidy = balance.basisPoints - rent.basisPoints
32
33 if (unusedSubsidy > 0n) {
34 await withdrawSubsidy(umi, {
35 distribution,
36 recipient: umi.identity.publicKey,
37 amount: unusedSubsidy,
38 }).sendAndConfirm(umi)
39 }
40}
41
42// 50000 token base units and any unused receipt subsidy are returned.
アクティブ区間は包含的です。startTime <= clusterTime <= endTime のとき出金は拒否されます。
未使用補助金 SOL を回収する
権限者は、補助金が有効で配布が非アクティブなときだけ、withdrawSubsidy で未使用レシート補助金を回収します。
withdrawSubsidy は要求された lamport 量を転送しつつ、配布アカウントの rent-exempt 最小額を維持します。想定クレームがすべて起きたと仮定せず、現在のアカウント残高から安全な量を決めてください。
配布残高を監視する
本番システムはプログラムの帳簿と実際の SPL / SOL アカウント残高を比較すべきです。
| 値 | 出典 | 意味 |
|---|---|---|
distribution.totalAmount | 配布アカウント | プログラムが記録した入金マイナス出金。クレームでは減らない |
| Vault token amount | 配布 associated token account | 実際に転送可能なトークン |
| Distribution lamports | 配布 PDA アカウント | 家賃準備金と任意の未使用レシート補助金 |
claimCount | 配布アカウント | 記録された成功クレーム数 |
claimAmount | 配布アカウント | 記録されたクレーム済みトークン最小単位の合計 |
トークン出金の帳簿は saturating subtraction を使うため、連携側は totalAmount が SPL ボールト残高と決して乖離しないと仮定しないでください。
注意事項
資金操作には権限者制御と明示的な残高監視が必要です。
- 現在の配布権限者だけが入金を承認できます。
- 入金はクレーム期間の前、最中、後に可能です。
- トークンと補助金の出金はアクティブ期間中ブロックされます。
- 誰でも配布 PDA へ SOL を直接送れますが、プログラム経由で補助金を引き出せるのは権限者だけです。
- クレームレシートは現在クローズできないため、レシート家賃は割り当てられたままです。
FAQ
クレームがアクティブな間、権限者はトークンを引き出せますか?
いいえ。トークン出金は開始タイムスタンプから終了タイムスタンプまで(両端含む)拒否されます。
subsidizeReceipts はどの費用を補填しますか?
クレームレシート家賃のみです。プロトコル手数料、トランザクション手数料、受取人トークンアカウント家賃は対象外です。
クレーム開始後にトークンを追加で入金できますか?
はい。入金に時間制限はないため、権限者は資金不足のボールトを補充できます。
配布権限者なしでトレジャリーウォレットが入金できますか?
いいえ。別の入金者がトークンを供給する場合でも、現在の権限者が deposit に署名する必要があります。
