I'm trying to create SPL token with Non-Transferable Extension with metadata. Right now I can create token with each features only follow these guides, and fails to combine them. below is how I tried to create Non-transferable token with metadata.
const { connection } = useConnection();
const { publicKey : walletPublicKey, sendTransaction } = useWallet();
const deployTokenSolana = useCallback(async () => {
// Generate new keypair for Mint Account
const mintKeypair = Keypair.generate();
// Address for Mint Account
const mint = mintKeypair.publicKey;
// Authority that can mint new tokens
const mintAuthority = walletPublicKey;
const tokenATA = await getAssociatedTokenAddressSync(mintKeypair.publicKey, walletPublicKey, false, TOKEN_2022_PROGRAM_ID);
// Metadata to store in Mint Account
const metaData: TokenMetadata = {
updateAuthority: walletPublicKey,
mint: mint,
name: "OPOS",
symbol: "OPOS",
uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json",
additionalMetadata: [
["description", "Only Possible On Solana"]
],
};
// Size of MetadataExtension 2 bytes for type, 2 bytes for length
const metadataExtension = TYPE_SIZE + LENGTH_SIZE;
// Size of metadata
const metadataLen = pack(metaData).length;
// Size of Mint Account with extension
const mintLenNT = getMintLen([ExtensionType.NonTransferable]);
const mintLenMP = getMintLen([ExtensionType.MetadataPointer]);
const mintLen = mintLenNT + mintLenMP
// Minimum lamports required for Mint Account
const lamports = await connection.getMinimumBalanceForRentExemption(
mintLen + metadataExtension + metadataLen
);
// Instruction to invoke System Program to create new account
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: walletPublicKey, // Account that will transfer lamports to created account
newAccountPubkey: mint, // Address of the account to create
space: mintLen, // Amount of bytes to allocate to the created account
lamports, // Amount of lamports transferred to created account
programId: TOKEN_2022_PROGRAM_ID, // Program assigned as owner of created account
});
// Instruction to initialize the MetadataPointer Extension
const initializeMetadataPointerInstruction =
createInitializeMetadataPointerInstruction(
mint, // Mint Account address
walletPublicKey, // Authority that can set the metadata address
mint, // Account address that holds the metadata
TOKEN_2022_PROGRAM_ID
);
// Instruction to initialize the NonTransferable Extension
const initializeNonTransferableMintInstruction =
createInitializeNonTransferableMintInstruction(
mint, // Mint Account address
TOKEN_2022_PROGRAM_ID, // Token Extension Program ID
);
// Instruction to initialize Mint Account data
const initializeMintInstruction = createInitializeMintInstruction(
mint, // Mint Account Address
tokenDecimals, // Decimals of Mint
mintAuthority, // Designated Mint Authority
walletPublicKey, // Optional Freeze Authority
TOKEN_2022_PROGRAM_ID, // Token Extension Program ID
);
// Instruction to initialize Metadata Account data
const initializeMetadataInstruction = createInitializeInstruction({
programId: TOKEN_2022_PROGRAM_ID, // Token Extension Program as Metadata Program
metadata: mint, // Account address that holds the metadata
updateAuthority: walletPublicKey, // Authority that can update the metadata
mint: mint, // Mint Account address
mintAuthority: mintAuthority, // Designated Mint Authority
name: metaData.name,
symbol: metaData.symbol,
uri: metaData.uri,
});
// Instruction to update metadata, adding custom field
const updateFieldInstruction = createUpdateFieldInstruction({
programId: TOKEN_2022_PROGRAM_ID, // Token Extension Program as Metadata Program
metadata: mint, // Account address that holds the metadata
updateAuthority: updateAuthority, // Authority that can update the metadata
field: metaData.additionalMetadata[0][0], // key
value: metaData.additionalMetadata[0][1], // value
});
const associatedTokenAccountInstruction = createAssociatedTokenAccountInstruction(
walletPublicKey,
tokenATA,
walletPublicKey,
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID
);
const mintToInstruction = createMintToInstruction(
mintKeypair.publicKey,
tokenATA,
walletPublicKey,
tokenTotalSupply * Math.pow(10, tokenDecimals),
undefined,
TOKEN_2022_PROGRAM_ID
);
// Add instructions to new transaction
const transaction = new Transaction().add(
createAccountInstruction,
initializeMetadataPointerInstruction,
initializeNonTransferableMintInstruction,
initializeMintInstruction,
initializeMetadataInstruction,
associatedTokenAccountInstruction,
mintToInstruction
);
const signature = await sendTransaction(transaction, connection, { signers: [mintKeypair] });
console.log(
"\nCreate Mint Account:",
`https://solana.fm/tx/${signature}?cluster=devnet-solana`
);
}, [walletPublicKey, connection, sendTransaction]);
Can anyone tell me what I'm doing wrong here?, or if there's any other approaches to implement this. Thanks