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.

legacyNftAllocations.ts
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.

claimLegacyNft.ts
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.

sponsoredLegacyNftClaim.ts
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 componentValue
Recipient seedNFT mint, not owner wallet
DestinationCurrent owner's associated token account for the distributed mint
Ownership transfer effectChanges who may receive an unclaimed allocation
Repeat claim after transferRejected 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.

ModeClaim signer requirement
PermissionlessAny payer may submit for the verified current owner
RecipientThe current nftOwner must sign
PermissionedThe 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:

  1. Mint eligibility model: Eligible NFT mints can claim regardless of later transfer, and the owner at claim time receives the reward.
  2. 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.