Distribution Types
Legacy NFT Distribution
Last updated August 26, 2026
Legacy NFT distributions assign token allocations to NFT mint addresses and pay the wallet that owns each NFT when the claim executes.
Summary
A LegacyNft distribution uses the legacy NFT mint as the Merkle leaf and verifies its current SPL token-account owner during distributeToLegacyNft.
- Build the allocation tree from NFT mint addresses rather than owner wallets.
- Create the distribution with
DistributionType.LegacyNft. - Send distributed tokens to the current owner's token account.
- Record the receipt against the NFT mint so an ownership transfer cannot enable a second claim.
Legacy NFTs Only
This flow validates an original SPL Token account with balance one. Token Metadata NFTs and pNFTs on that token program qualify. It is not compatible with MPL Core assets or Token-2022 NFTs.
Legacy NFT Allocation Model
Each allocation commits a legacy NFT mint address, token amount, and optional 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
Do not build the leaves from snapshot owner wallets. The NFT mint is the stable identity that lets ownership transfer before a claim.
Legacy NFT Ownership Verification
The program verifies current ownership from the NFT's SPL token account at claim time.
The supplied NFT token account must:
- Be owned by the original SPL Token program.
- Use the NFT mint committed in the Merkle leaf.
- Hold exactly one token.
- Be owned by the supplied
nftOwner.
The program does not call Token Metadata, Token Record, or Authorization Rules. It only checks the SPL token account listed above.
Submit a Legacy NFT Claim
The distributeToLegacyNft instruction verifies the mint proof and sends tokens to the current NFT owner's 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.
When nftOwner is omitted, the SDK defaults it to the transaction payer and derives that payer's NFT token account. Supply nftOwner explicitly when a permissionless service pays on behalf of another owner.
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.
Legacy NFT Claim Receipt
The legacy NFT receipt stores the NFT mint as its recipient identity.
| Receipt component | Value |
|---|---|
| Recipient seed | NFT mint, not owner wallet |
| Destination | Current owner's associated token account for the distributed mint |
| Ownership transfer effect | Changes who may receive an unclaimed allocation |
| Repeat claim after transfer | Rejected because the receipt remains tied to the NFT mint |
Legacy NFT Distribution Access Modes
The allowed distributor mode applies to the NFT owner rather than the NFT mint.
| Mode | Claim signer requirement |
|---|---|
Permissionless | Any payer may submit for the verified current owner |
Recipient | The current nftOwner must sign |
Permissioned | The configured permissioned distributor must sign |
Use Recipient when the current holder must opt in. Use Permissionless when a relayer can pay the claim for the verified current owner without that owner signing.
Legacy NFT Snapshot Considerations
The Merkle tree fixes eligible NFT mints while ownership remains dynamic until each mint claims.
This distinction creates two common models:
- Mint eligibility model: Eligible NFT mints can claim regardless of later transfer, and the owner at claim time receives the reward.
- Owner snapshot model: Snapshot owner wallets instead and use a Wallet distribution when transfer after the snapshot must not move eligibility.
Prevent Marketplace Surprises
Publish whether eligibility follows the NFT mint or the snapshot owner. A buyer can receive an unclaimed mint-based allocation, but cannot determine claim status from ownership alone; the application should check the claim receipt.
Notes
Legacy NFT distributions verify fungible token-account facts rather than complete NFT metadata semantics.
- Collection verification and NFT eligibility must happen before root generation.
- Frozen or delegated NFT token accounts still need application-level review.
- The reward token goes to the NFT owner's canonical associated token account.
- The current program does not close claim receipts after redemption.
FAQ
Who receives an allocation after the NFT is transferred?
The wallet that owns the NFT token account when the claim executes receives the allocation.
Can a later NFT owner claim again?
No. The claim receipt is keyed by the NFT mint, amount, and nonce, so ownership transfer does not reset it.
Can this flow distribute tokens to MPL Core asset holders?
No. LegacyNft validates SPL token-account ownership; Core assets require the Wallet distribution asset-signer pattern.
Does LegacyNft work for pNFTs?
Yes, when the pNFT token account is owned by the original SPL Token program and holds a balance of one. The program does not call Token Metadata, Token Record, or Authorization Rules. Token-2022 pNFTs are not supported.
