操作

資金投入と回収

Last updated August 26, 2026

MPL-Distro は、配布ボールトのトークン資金と、クレームレシート家賃用の任意 SOL 資金を分けます。

概要

権限者は SPL トークンを配布の associated token account へ入金し、レシート補助金が有効なときは配布 PDA に SOL を入れることができます。

  • すべての Merkle 割り当てをカバーする十分なトークン最小単位を入金します。
  • 成功が想定されるクレームごとに 1 回のクレームレシート家賃を予算化します。
  • 記録された totalAmount と実際のボールトトークン残高の両方を監視します。
  • 配布が非アクティブなときだけ、未クレームトークンと未使用補助金 SOL を引き出します。

クイックスタート

MPL-Distro の資金投入と回収は 4 つの運用手順に従います。

  1. すべての割り当て量を合計し、そのトークン最小単位を入金します。
  2. レシート補助金が有効なときは、想定レシート家賃予算を配布 PDA へ転送します。
  3. 実際のボールト残高、配布 SOL、クレーム合計を監視します。
  4. 期間終了後、未クレームトークンと未使用補助金 SOL を引き出します。

配布トークンを入金する

deposit 命令は入金者のアカウントから配布 PDA の正規 associated token account へトークンを転送します。別ウォレットがトークンを供給する場合でも、現在の配布権限者がすべての入金に署名する必要があります。

fundDistribution.ts
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 は depositorpayerauthority を Umi 支払者にデフォルトし、両方の associated token account を導出します。別ウォレットが元トークンを所有するときは別の入金者署名者を渡し、現在の配布権限者も渡します。

depositFromSeparateWallet.ts
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 の最小単位で表したすべての割り当て量の合計です。

calculateDeposit.ts
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 へ直接転送します。

fundReceiptSubsidy.ts
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 で未クレームまたは余りのトークンを回収します。

recoverFunds.ts
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 に署名する必要があります。