Features
Transferring Assets
The owner of an asset can transfer it to another account by sending a Transfer instruction to the Token Metadata program. This instruction accepts the following attributes:
- Authority: The signer that authorized the transfer. Typically, this is the owner of the asset but note that certain delegated authorities can also transfer assets on behalf of the owner as discussed in the "Delegated Authorities" page.
- Token Owner: The public key of the current owner of the asset.
- Destination Owner: The public key of the new owner of the asset.
- Token Standard: The standard of the asset being transferred. This instruction works for all Token Standards in order to provide a unified interface for transferring assets. That being said, it is worth noting that non-programmable assets can be transferred using the Transfer instruction of the SPL Token program directly.
Here is how you can use our SDKs to transfer an asset on Token Metadata.
Transfer NFT
1import { publicKey } from '@metaplex-foundation/umi';
2import {
3 transferV1,
4 TokenStandard,
5} from '@metaplex-foundation/mpl-token-metadata';
6
7// Assuming umi is set up with mplTokenMetadata plugin
8// See getting-started for full setup
9
10const mintAddress = publicKey('mintAddress...');
11const currentOwner = umi.identity; // Current token owner
12const destinationOwner = publicKey('destinationWallet...');
13
14// Transfer the NFT to a new owner
15await transferV1(umi, {
16 mint: mintAddress,
17 authority: currentOwner,
18 tokenOwner: currentOwner.publicKey,
19 destinationOwner,
20 tokenStandard: TokenStandard.NonFungible,
21}).sendAndConfirm(umi);
22
23console.log('NFT transferred to:', destinationOwner);
1import {
2 getTransferV1InstructionAsync,
3 TokenStandard,
4} from '@metaplex-foundation/mpl-token-metadata-kit';
5
6// Assuming rpc, rpcSubscriptions, sendAndConfirm, and authority are set up
7// See getting-started for full setup
8
9const mintAddress = 'mintAddress...'; // The NFT mint address
10const currentOwner = authority.address; // Current token owner
11const destinationOwner = 'destinationWallet...'; // New owner address
12
13// Transfer the NFT to a new owner
14const transferIx = await getTransferV1InstructionAsync({
15 mint: mintAddress,
16 tokenOwner: currentOwner,
17 destinationOwner,
18 authority,
19 payer: authority,
20 tokenStandard: TokenStandard.NonFungible,
21});
22
23await sendAndConfirm({
24 instructions: [transferIx],
25 payer: authority,
26});
27
28console.log('NFT transferred to:', destinationOwner);
Transfer pNFT
Programmable NFTs (pNFTs) may have additional authorization rules that need to be handled during transfer. The instruction will automatically handle Token Record accounts.
1import { publicKey } from '@metaplex-foundation/umi';
2import {
3 transferV1,
4 TokenStandard,
5} from '@metaplex-foundation/mpl-token-metadata';
6
7// Assuming umi is set up with mplTokenMetadata plugin
8
9const mintAddress = publicKey('mintAddress...');
10const currentOwner = umi.identity;
11const destinationOwner = publicKey('destinationWallet...');
12
13// Transfer the Programmable NFT to a new owner
14// Note: pNFTs require additional Token Record accounts handled automatically
15await transferV1(umi, {
16 mint: mintAddress,
17 authority: currentOwner,
18 tokenOwner: currentOwner.publicKey,
19 destinationOwner,
20 tokenStandard: TokenStandard.ProgrammableNonFungible,
21}).sendAndConfirm(umi);
22
23console.log('pNFT transferred to:', destinationOwner);
1import {
2 getTransferV1InstructionAsync,
3 TokenStandard,
4} from '@metaplex-foundation/mpl-token-metadata-kit';
5
6// Assuming rpc, rpcSubscriptions, sendAndConfirm, and authority are set up
7
8const mintAddress = 'mintAddress...'; // The pNFT mint address
9const currentOwner = authority.address;
10const destinationOwner = 'destinationWallet...';
11
12// Transfer the Programmable NFT to a new owner
13// Note: pNFTs require additional Token Record accounts handled automatically
14const transferIx = await getTransferV1InstructionAsync({
15 mint: mintAddress,
16 tokenOwner: currentOwner,
17 destinationOwner,
18 authority,
19 payer: authority,
20 tokenStandard: TokenStandard.ProgrammableNonFungible,
21});
22
23await sendAndConfirm({
24 instructions: [transferIx],
25 payer: authority,
26});
27
28console.log('pNFT transferred to:', destinationOwner);
Advanced pNFT Transfer
For pNFTs with complex authorization rules, you may need to provide additional parameters.
1import { getMplTokenAuthRulesProgramId } from '@metaplex-foundation/mpl-candy-machine';
2import {
3 fetchDigitalAssetWithAssociatedToken,
4 findTokenRecordPda,
5 TokenStandard,
6 transferV1,
7} from '@metaplex-foundation/mpl-token-metadata';
8import { findAssociatedTokenPda } from '@metaplex-foundation/mpl-toolbox';
9import { publicKey, unwrapOptionRecursively } from '@metaplex-foundation/umi';
10import { base58 } from '@metaplex-foundation/umi/serializers';
11
12// The NFT Asset Mint ID
13const mintId = publicKey('11111111111111111111111111111111');
14
15// The destination wallet
16const destinationAddress = publicKey('22222222222222222222222222222222');
17
18// Fetch the pNFT Asset with the Token Account
19const assetWithToken = await fetchDigitalAssetWithAssociatedToken(
20 umi,
21 mintId,
22 umi.identity.publicKey
23);
24
25// Calculates the destination wallet's Token Account
26const destinationTokenAccount = findAssociatedTokenPda(umi, {
27 mint: mintId,
28 owner: destinationAddress,
29});
30
31// Calculates the destinations wallet's Token Record Account
32const destinationTokenRecord = findTokenRecordPda(umi, {
33 mint: mintId,
34 token: destinationTokenAccount[0],
35});
36
37// Transfer the pNFT
38const { signature } = await transferV1(umi, {
39 mint: mintId,
40 destinationOwner: destinationAddress,
41 destinationTokenRecord: destinationTokenRecord,
42 tokenRecord: assetWithToken.tokenRecord?.publicKey,
43 tokenStandard: TokenStandard.ProgrammableNonFungible,
44 // Check to see if the pNFT asset as auth rules.
45 authorizationRules:
46 unwrapOptionRecursively(assetWithToken.metadata.programmableConfig)
47 ?.ruleSet || undefined,
48 // Auth rules program ID
49 authorizationRulesProgram: getMplTokenAuthRulesProgramId(umi),
50 // Some pNFTs may require authorization data if set.
51 authorizationData: undefined,
52}).sendAndConfirm(umi);
53
54console.log('Signature:', base58.deserialize(signature));
1import { address } from '@solana/addresses';
2import {
3 getTransferV1InstructionAsync,
4 TokenStandard,
5} from '@metaplex-foundation/mpl-token-metadata-kit';
6
7// Assuming rpc, sendAndConfirm, and authority are set up
8
9const mintAddress = address('mintAddress...'); // Your pNFT mint address
10const currentOwner = authority.address;
11const destinationOwner = address('destinationWallet...'); // Destination wallet
12
13// For pNFTs with auth rules, the SDK handles most resolution automatically
14const transferIx = await getTransferV1InstructionAsync({
15 mint: mintAddress,
16 tokenOwner: currentOwner,
17 destinationOwner,
18 authority,
19 payer: authority,
20 tokenStandard: TokenStandard.ProgrammableNonFungible,
21 // Auth rules are resolved automatically when available
22});
23
24await sendAndConfirm({
25 instructions: [transferIx],
26 payer: authority,
27});
28
29console.log('pNFT transferred to:', destinationOwner);
