1

Following guides, https://solana.com/developers/guides/token-extensions/non-transferable#build-instructions and https://solana.com/developers/guides/token-extensions/immutable-owner#conclusion They can work well separately. However, if I put them together, immutable-owner always shows

Error processing Instruction 2: invalid account data for instruction.

My code is based on guide.

import * as anchor from "@coral-xyz/anchor";
 import {Program, web3} from "@coral-xyz/anchor";
import { Sol } from "../target/types/sol";
import {it} from "mocha";
import {Connection, Keypair, sendAndConfirmTransaction, SystemProgram, Transaction} from "@solana/web3.js";
import {
AuthorityType,
createInitializeAccountInstruction,
createInitializeImmutableOwnerInstruction,
createInitializeMintInstruction,
createInitializeNonTransferableMintInstruction,
createMint,
ExtensionType,
getAccountLen, getMintLen, setAuthority,
TOKEN_2022_PROGRAM_ID
} from "@solana/spl-token";
import {min} from "bn.js";

//anchor test
describe("sol", () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.env());

const program = anchor.workspace.Sol as Program<Sol>;
const Seed = anchor.utils.bytes.utf8.encode("conf");

let adminPubKey;

before( async () => {
    [adminPubKey] = await anchor.web3.PublicKey.findProgramAddress(
        [Seed, anchor.AnchorProvider.env().wallet.publicKey.toBytes()],
        program.programId
    );
});
it( "Is createAdmin", async () => {
    const payer = web3.Keypair.generate();

// Connection to devnet cluster
    const connection = new Connection('http://127.0.0.1:8899', 'confirmed');

 // Transaction signature returned from sent transaction
    let transactionSignature: string;

    const airdropSignature = await connection.requestAirdrop(
        payer.publicKey,
        web3.LAMPORTS_PER_SOL, // 1 SOL
    );
    await connection.confirmTransaction(airdropSignature);
    const balanceA = await connection.getBalance(payer.publicKey)
    console.log("airdropSignature success", balanceA);


    // Authority that can mint new tokens
    const mintAuthority = payer.publicKey;
   // Decimals for Mint Account
    const decimals = 2;



    

    const mintLen = getMintLen([ExtensionType.NonTransferable]);
  // Minimum lamports required for Mint Account
    let lamports = await connection.getMinimumBalanceForRentExemption(mintLen);

    const mintKeypair = Keypair.generate();
 // Address for Mint Account
    const mint = mintKeypair.publicKey;

    const createAccountInstructionA = SystemProgram.createAccount({
        fromPubkey: payer.publicKey, // 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
    });
    console.log("createAccountInstruction",createAccountInstructionA)

  // Instruction to initialize the NonTransferable Extension
    const initializeNonTransferableMintInstructionA =
        createInitializeNonTransferableMintInstruction(
            mint, // Mint Account address
            TOKEN_2022_PROGRAM_ID, // Token Extension Program ID
        );
    



    // Instruction to initialize Mint Account data
    const initializeMintInstructionA = createInitializeMintInstruction(
        mint, // Mint Account Address
        decimals, // Decimals of Mint
        anchor.AnchorProvider.env().publicKey, // Designated Mint Authority
        null, // Optional Freeze Authority
        TOKEN_2022_PROGRAM_ID, // Token Extension Program ID
    );
    console.log("initializeMintInstruction",initializeMintInstructionA)
    // Add instructions to new transaction
    const transactionA = new Transaction().add(
        createAccountInstructionA,
        initializeNonTransferableMintInstructionA,
        initializeMintInstructionA,
    );
    console.log("mint:",mint)

    // Send transaction
    transactionSignature = await sendAndConfirmTransaction(
        connection,
        transactionA,
        [payer, mintKeypair], // Signers
    );

    console.log(
        "transactionSignature",transactionSignature
    )








    // Random keypair to use as owner of Token Account
    const tokenAccountKeypair = Keypair.generate();
    // Address for Token Account
    const tokenAccount = tokenAccountKeypair.publicKey;

    // Size of Token Account with extension
    const accountLen = getAccountLen([ExtensionType.ImmutableOwner]);
    // Minimum lamports required for Token Account
     lamports = await connection.getMinimumBalanceForRentExemption(accountLen);


    // Instruction to invoke System Program to create new account
    const createAccountInstruction = SystemProgram.createAccount({
        fromPubkey: payer.publicKey, // Account that will transfer lamports to created account
        newAccountPubkey: tokenAccount, // Address of the account to create
        space: accountLen, // 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 ImmutableOwner Extension
    const initializeImmutableOwnerInstruction =
        createInitializeImmutableOwnerInstruction(
            tokenAccount, // Token Account address
            TOKEN_2022_PROGRAM_ID, // Token Extension Program ID
        );

    // Instruction to initialize Token Account data
    const initializeAccountInstruction = createInitializeAccountInstruction(
        tokenAccount, // Token Account Address
        mint, // Mint Account
        payer.publicKey, // Token Account Owner
        TOKEN_2022_PROGRAM_ID, // Token Extension Program ID
    );
    console.log("mint:",mint)

    // Add instructions to new transaction
    const transaction = new Transaction().add(
        createAccountInstruction,
       // initializeImmutableOwnerInstruction,
        initializeAccountInstruction,
    );

   // Send transaction
    transactionSignature = await sendAndConfirmTransaction(
        connection,
        transaction,
        [payer, tokenAccountKeypair], // Signers
    );

    console.log(
        "\nCreate Token Account:",
        `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`,
    );




    


})





});

1 Answer 1

1

The provided account length won't be enough, because you also need to include space for the NonTransferableAccount extension. I think it should work if you just change the line creating accountLen to:

    const accountLen = getAccountLen([ExtensionType.ImmutableOwner, ExtensionType.NonTransferableAccount]);

You can start by running the end-to-end tests for the non-transferable extension at https://github.com/solana-labs/solana-program-library/blob/646efc13449fa6e1a8f69d767283478d2a0002e4/token/js/test/e2e-2022/nonTransferableMint.test.ts#L54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.