配布タイプ
レガシー NFT 配布
Last updated August 26, 2026
レガシー NFT 配布は NFT mint アドレスにトークン割り当てを付け、クレーム実行時に各 NFT を所有するウォレットへ支払います。
概要
LegacyNft 配布はレガシー NFT mint を Merkle リーフとして使い、distributeToLegacyNft 中に現在の SPL トークンアカウント所有者を検証します。
- 所有者ウォレットではなく NFT mint アドレスから割り当てツリーを構築します。
DistributionType.LegacyNftで配布を作成します。- 配布トークンを現在の所有者のトークンアカウントへ送ります。
- NFT mint に対してレシートを記録し、所有権移転で 2 回目のクレームができないようにします。
レガシー NFT のみ
このフローは残高 1 のオリジナル SPL Token アカウントを検証します。そのトークンプログラム上の Token Metadata NFT と pNFT が対象です。MPL Core アセットや Token-2022 NFT とは互換ではありません。
レガシー NFT 割り当てモデル
各割り当てはレガシー NFT mint アドレス、トークン量、任意の nonce をコミットします。
1import {
2 DistributionType,
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
13const nftMintA = publicKey(process.env.LEGACY_NFT_MINT_A!)
14const nftMintB = publicKey(process.env.LEGACY_NFT_MINT_B!)
15
16const allocations = [
17 { address: nftMintA, amount: 100_000n },
18 { address: nftMintB, amount: 100_000n },
19]
20
21const { root, proofs, treeHeight } = prepareDistribution(allocations)
22
23const distributionFields = {
24 merkleRoot: root,
25 treeHeight,
26 totalClaimants: BigInt(allocations.length),
27 distributionType: DistributionType.LegacyNft,
28}
29
30console.log(distributionFields, proofs.length)
31
32// Root, treeHeight, and LegacyNft fields for createDistribution
スナップショット所有者ウォレットからリーフを構築しないでください。NFT mint が安定した identity であり、クレーム前の所有権移転を許します。
レガシー NFT の所有権検証
プログラムはクレーム時に NFT の SPL トークンアカウントから現在の所有権を検証します。
渡された NFT トークンアカウントは次を満たす必要があります。
- オリジナル SPL Token プログラム所有であること。
- Merkle リーフにコミットされた NFT mint を使うこと。
- ちょうど 1 トークンを保持すること。
- 渡された
nftOwnerが所有者であること。
プログラムは Token Metadata、Token Record、Authorization Rules を呼びません。上記の SPL トークンアカウントだけを確認します。
レガシー NFT クレームを送信する
distributeToLegacyNft 命令は mint 証明を検証し、現在の NFT 所有者の associated token account へトークンを送ります。
1import {
2 distributeToLegacyNft,
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// Default nftOwner to the Umi identity, or pass nftOwner explicitly
14// for a sponsored claim.
15
16const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
17const mint = publicKey(process.env.TOKEN_MINT!)
18const nftMint = publicKey(process.env.LEGACY_NFT_MINT!)
19const allocations = [{ address: nftMint, amount: 100_000n }]
20const { proofs } = prepareDistribution(allocations)
21
22await distributeToLegacyNft(umi, {
23 distribution,
24 mint,
25 nftMint,
26 amount: allocations[0].amount,
27 proof: proofs[0],
28 nonce: 0,
29}).sendAndConfirm(umi)
30
31// The current NFT owner's ATA receives 100000 base units.
32// The receipt is keyed by the NFT mint, so the allocation cannot be claimed twice.
nftOwner を省略すると、SDK はトランザクション支払者をデフォルトにし、その支払者の NFT トークンアカウントを導出します。Permissionless サービスが別の所有者の代わりに支払うときは nftOwner を明示してください。
1import {
2 distributeToLegacyNft,
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
12const airdropService = umi.payer
13const distribution = publicKey(process.env.DISTRIBUTION_ADDRESS!)
14const rewardMint = publicKey(process.env.TOKEN_MINT!)
15const nftMint = publicKey(process.env.LEGACY_NFT_MINT!)
16const currentOwner = publicKey(process.env.NFT_OWNER!)
17const amount = 100_000n
18const proof = []
19const nonce = 0
20
21await distributeToLegacyNft(umi, {
22 payer: airdropService,
23 distribution,
24 mint: rewardMint,
25 nftMint,
26 nftOwner: currentOwner,
27 amount,
28 proof,
29 nonce,
30}).sendAndConfirm(umi)
31
32// The current NFT owner's ATA receives the allocation.
レガシー NFT クレームレシート
レガシー NFT レシートは NFT mint を受取人 identity として保存します。
| レシート要素 | 値 |
|---|---|
| Recipient seed | NFT mint(所有者ウォレットではない) |
| Destination | 配布 mint に対する現在の所有者の associated token account |
| Ownership transfer effect | 未クレーム割り当ての受取人を変える |
| Repeat claim after transfer | レシートが NFT mint に結びついたままなので拒否される |
レガシー NFT 配布のアクセスモード
Allowed distributor モードは NFT mint ではなく NFT 所有者に適用されます。
| モード | クレーム署名者の要件 |
|---|---|
Permissionless | 検証済みの現在の所有者のために任意の支払者が送信できる |
Recipient | 現在の nftOwner が署名する必要がある |
Permissioned | 設定された permissioned distributor が署名する必要がある |
現在の保有者がオプトインする必要があるときは Recipient を使います。検証済みの現在の所有者が署名せず、リレイヤーがクレームを支払えるときは Permissionless を使います。
レガシー NFT スナップショットの考慮点
Merkle ツリーは対象 NFT mint を固定しますが、各 mint がクレームするまで所有権は動的です。
この区別からよくある 2 つのモデルが生まれます。
- Mint 適格モデル: 後の転送に関係なく対象 NFT mint はクレームでき、クレーム時の所有者が報酬を受け取ります。
- 所有者スナップショットモデル: スナップショット後の転送で適格性を動かしたくないときは、スナップショット所有者ウォレットを使い ウォレット配布 にします。
マーケットプレイスの驚きを防ぐ
適格性が NFT mint に従うのかスナップショット所有者に従うのかを公開してください。買い手は未クレームの mint ベース割り当てを受け取れますが、所有権だけではクレーム状態を判断できません。アプリケーションがクレームレシートを確認すべきです。
注意事項
レガシー NFT 配布は完全な NFT メタデータ意味論ではなく、ファンジブルなトークンアカウントの事実を検証します。
- コレクション検証と NFT 適格性はルート生成前に行う必要があります。
- 凍結または委任された NFT トークンアカウントはアプリケーション層での確認が必要です。
- 報酬トークンは NFT 所有者の正規 associated token account へ行きます。
- 現行プログラムは償還後にクレームレシートをクローズしません。
FAQ
NFT が転送された後、誰が割り当てを受け取りますか?
クレーム実行時に NFT トークンアカウントを所有するウォレットが割り当てを受け取ります。
後の NFT 所有者が再クレームできますか?
いいえ。クレームレシートは NFT mint、amount、nonce でキーされるため、所有権移転ではリセットされません。
このフローで MPL Core アセット保有者へトークンを配布できますか?
いいえ。LegacyNft は SPL トークンアカウントの所有権を検証します。Core アセットには Wallet 配布のアセットサイナーパターンが必要です。
LegacyNft は pNFT で動きますか?
はい。pNFT トークンアカウントがオリジナル SPL Token プログラム所有で残高 1 のときです。プログラムは Token Metadata、Token Record、Authorization Rules を呼びません。Token-2022 pNFT は非対応です。
