I am trying to build a token that I could airdrop to an account, and not be able to be transferred between accounts.
I had two ideas:TOKEN_2022 Unfreeze Account -> Mint -> Freeze AccountTOKEN_2022 Non Transferable Mint with Metadata
Now when trying to create a Mint account TOKEN_2022_Program in the same instruction with the Non Transferable Mint and createCreateMetadataAccountV3Instruction I get the following error:
'Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s invoke [1]'
'Program log: Instruction not supported for ProgrammableNonFungible assets'
This is the code for it:
import { getExplorerLink, getKeypairFromEnvironment,} from "@solana-developers/helpers";import { clusterApiUrl, Connection, Keypair, PublicKey, sendAndConfirmTransaction, Transaction,} from "@solana/web3.js";import web3 from "@solana/web3.js";import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, MINT_SIZE, getMinimumBalanceForRentExemptMint, createInitializeNonTransferableMintInstruction, createInitializeMintInstruction, getMintLen, ExtensionType,} from "@solana/spl-token";import { createCreateMetadataAccountV3Instruction } from "@metaplex-foundation/mpl-token-metadata";const TOKEN_METADATA_PROGRAM_ID = new web3.PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");//Freeze the authorityexport async function initMint() { const { connection, keyPair, mintKeypair, mintPK, freezeAuthority, uri, mintLen, decimals, programId, lamports, } = await getConnHelpers(); //Metadata account const metadataPdaAndBump = web3.PublicKey.findProgramAddressSync( [ Buffer.from("metadata"), TOKEN_METADATA_PROGRAM_ID.toBuffer(), mintPK.toBuffer(), ], TOKEN_METADATA_PROGRAM_ID ); const metadataData = { name: "name", symbol: "name", uri: uri, sellerFeeBasisPoints: 0, creators: null, collection: null, uses: null, }; const metadataPda = metadataPdaAndBump[0]; const createMetadataAccountInstruction = createCreateMetadataAccountV3Instruction( { metadata: metadataPda, mint: mintPK, mintAuthority: keyPair.publicKey, payer: keyPair.publicKey, updateAuthority: keyPair.publicKey, }, { createMetadataAccountArgsV3: { collectionDetails: null, data: metadataData, isMutable: false, }, } ); //Non transferrable token mint extension const initializeNonTransferableMintInstruction = createInitializeNonTransferableMintInstruction(mintPK, programId); const createMintInstruction = [ web3.SystemProgram.createAccount({ fromPubkey: keyPair.publicKey, newAccountPubkey: mintPK, space: mintLen, lamports, programId, }), createInitializeNonTransferableMintInstruction( mintKeypair.publicKey, programId ), createInitializeMintInstruction( mintKeypair.publicKey, decimals, keyPair.publicKey, null, programId ), ]; const tx = new Transaction(); tx.add(...createMintInstruction); tx.add(createMetadataAccountInstruction); const signature = await sendAndConfirmTransaction(connection, tx, [ keyPair, mintKeypair, ]); const link = getExplorerLink("transaction", signature, "devnet"); console.log(link);}async function getConnHelpers() { const connection = new Connection(clusterApiUrl("devnet")); const keyPair = getKeypairFromEnvironment("SECRET_KEY"); const mintKeypair = Keypair.generate(); const mintPK = mintKeypair.publicKey; const freezeAuthority = mintKeypair.publicKey; const uri = "jsonurl"; const mintLen = getMintLen([ExtensionType.NonTransferable]); const decimals = 2; const programId = TOKEN_2022_PROGRAM_ID; const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); return { connection, keyPair, mintKeypair, mintPK, freezeAuthority, uri, mintLen, decimals, programId, lamports, };}
If you have any other idea to have a token with metadata, with the possibility to be minted and not transferrable between token accounts, please leave idea.