2

I used the Solana Playground wallet to deploy a program and obtained the program ID. The ID is 6baxXgMr7HypeTBhN64rbrt31UwbSeRtsQQxGw1KBi5b. Then, I used the following script to create an SPL token.

//createandmint.js
const {
    clusterApiUrl,
    sendAndConfirmTransaction,
    Connection,
    Keypair,
    PublicKey,
    SystemProgram,
    Transaction,
    LAMPORTS_PER_SOL,
} =require('@solana/web3.js');

const {
    ExtensionType,
    createInitializeMintInstruction,
    createInitializeTransferHookInstruction,
    mintTo,
    createAccount,
    getMintLen,
    TOKEN_2022_PROGRAM_ID, createAssociatedTokenAccountIdempotent,
} =require("@solana/spl-token");
const bs58 = require("bs58");

(async () => {
    function generateExplorerTxUrl(txId) {
        return `https://explorer.solana.com/tx/${txId}?cluster=devnet`;
    }
    const privateKeyString = 'xxxxxxxxxxxx';
    let privateKeyBytes = bs58.decode(privateKeyString);
// Import our keypair from the wallet file
    const payer = Keypair.fromSecretKey(new Uint8Array(privateKeyBytes));



    // const payer = Keypair.generate();
    const mintAuthority = payer;

    const mintKeypair = Keypair.generate();
    const mint = mintKeypair.publicKey;

    const extensions = [ExtensionType.TransferHook];
    const mintLen = getMintLen(extensions);
    const decimals = 9;

    const mintAmount = BigInt(1_000_000 * Math.pow(10, decimals)); // Mint 1,000,000 tokens
    const transferAmount = BigInt(1_000 * Math.pow(10, decimals)); // Transfer 1,000 tokens

    const transferHookProgramId = new PublicKey('6baxXgMr7HypeTBhN64rbrt31UwbSeRtsQQxGw1KBi5b')

    const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');

    const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL);
    await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) });

    const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen);
    const mintTransaction = new Transaction().add(
        SystemProgram.createAccount({
            fromPubkey: payer.publicKey,
            newAccountPubkey: mint,
            space: mintLen,
            lamports: mintLamports,
            programId: TOKEN_2022_PROGRAM_ID,
        }),
        createInitializeTransferHookInstruction(mint, payer.publicKey, transferHookProgramId, TOKEN_2022_PROGRAM_ID),
        createInitializeMintInstruction(mint, decimals, mintAuthority.publicKey, null, TOKEN_2022_PROGRAM_ID)
    );
    const newTokenTx = await sendAndConfirmTransaction(connection, mintTransaction, [payer, mintKeypair], undefined);
    console.log("New Token Created:", generateExplorerTxUrl(newTokenTx));
    const owner = payer;
    const sourceAccount = await createAssociatedTokenAccountIdempotent(connection, payer, mint, owner.publicKey, {}, TOKEN_2022_PROGRAM_ID);
    const mintSig = await mintTo(connection,payer,mint,sourceAccount,mintAuthority,mintAmount,[],undefined,TOKEN_2022_PROGRAM_ID);
    console.log("Tokens Minted:", generateExplorerTxUrl(mintSig));

})()

https://explorer.solana.com/address/2ieG5FgkUS2VXKU8RKLePGJ5t18nGRUcEqJcr4jcgMjF?cluster=devnet Now I want to transfer spl token to a new wallet,the spl token mint address is 2ieG5FgkUS2VXKU8RKLePGJ5t18nGRUcEqJcr4jcgMjF

//transfer.js
const {
        PublicKey,
        SystemProgram,
        Transaction,
        sendAndConfirmTransaction,
        Keypair, Connection, clusterApiUrl,
    } =require("@solana/web3.js");
    const {
        ExtensionType,
        TOKEN_2022_PROGRAM_ID,
        getMintLen,
        createInitializeMintInstruction,
        createInitializeTransferHookInstruction,
        ASSOCIATED_TOKEN_PROGRAM_ID,
        createAssociatedTokenAccountInstruction,
        createMintToInstruction,
        createTransferCheckedInstruction,
        getAssociatedTokenAddressSync,
        createTransferCheckedWithTransferHookInstruction,
    } =require("@solana/spl-token");
    const bs58 = require("bs58");
    
    const privateKeyString = 'xxxxxxxxxxx';
    let privateKeyBytes = bs58.decode(privateKeyString);
    // Import our keypair from the wallet file
    const wallet = Keypair.fromSecretKey(new Uint8Array(privateKeyBytes));
    const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');
    // Generate keypair to use as address for the transfer-hook enabled mint
    const mint = new PublicKey("2ieG5FgkUS2VXKU8RKLePGJ5t18nGRUcEqJcr4jcgMjF");
    const decimals = 9;
    const amount = 1 * 10 ** decimals;
    const bigIntAmount = BigInt(amount);
    
    const sourceTokenAccount = getAssociatedTokenAddressSync(
        mint,
        wallet.publicKey,
        false,
        TOKEN_2022_PROGRAM_ID,
        ASSOCIATED_TOKEN_PROGRAM_ID
    );
    
    // Recipient token account address
    const recipient = Keypair.generate();
    const destinationTokenAccount = getAssociatedTokenAddressSync(
        mint,
        recipient.publicKey,
        false,
        TOKEN_2022_PROGRAM_ID,
        ASSOCIATED_TOKEN_PROGRAM_ID
    );
    (async () => {
        const transferInstruction =
            await createTransferCheckedWithTransferHookInstruction(
                connection,
                sourceTokenAccount,
                mint,
                destinationTokenAccount,
                wallet.publicKey,
                bigIntAmount,
                decimals,
                [],
                "confirmed",
                TOKEN_2022_PROGRAM_ID
            );
    
        const transaction = new Transaction().add(
            transferInstruction
        );
    
        const txSig = await sendAndConfirmTransaction(
            connection,
            transaction,
            [wallet],
            { skipPreflight: true }
        );
        console.log("Transfer Signature:", txSig);
    })()

npm install @solana/[email protected] and the result is

failed ({"err":{"InstructionError":[0,"IncorrectProgramId"]}})

Anything wrong here?

1 Answer 1

3

best follow this guide:

https://solana.com/developers/guides/token-extensions/transfer-hook

Here is a simple hello world example.

https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/transfer-hook/anchor/TransferHookHelloWorld

I cant really see an error in your code. I dont think you need to add these accounts:

transferInstruction.keys.push(
  {
    pubkey: program.programId, // Address of the Transfer-hook program
    isSigner: false,
    isWritable: false,
  },
  {
    pubkey: extraAccountMetaListPDA, // Address of the ExtraAccountMeta account
    isSigner: false,
    isWritable: false,
  }
);

Maybe you need to update to the newest spl-token version.

    "@solana/spl-token": "^0.4.3"

Maybe you need to redeploy the transfer hook program.

9
  • I apologize for being a beginner, but there has been an update to the question. @jonas-h
    – blueboy
    Commented Apr 12 at 14:35
  • Could you please try log all the keys of that instruction and then check if they are the correct ones? console.log( "Pushed keys:", JSON.stringify(transferInstruction.keys, null, 2) );
    – Jonas H.
    Commented Apr 12 at 14:44
  • All the keys are fine.link
    – blueboy
    Commented Apr 12 at 15:01
  • Pushed keys: [ { "pubkey": "BtX8y6Vk6tYjC8Whorcz2DrU2QMGQu5vG6LA59vuZNsu", "isSigner": false, "isWritable": true }, { "pubkey": "2ieG5FgkUS2VXKU8RKLePGJ5t18nGRUcEqJcr4jcgMjF", "isSigner": false, "isWritable": false }, { "pubkey": "EG3ERQTBUcF2xjqZMGesBjvw5QishKYGByLrTYxaCNJ7", "isSigner": false, "isWritable": true }, { "pubkey": "74aC1TdARVnebeVB13rRGsJtvuQV18WLYmJnSDh1DGWJ", "isSigner": true, "isWritable": false } ]
    – blueboy
    Commented Apr 12 at 15:04
  • 1
    on the explorer link in the comment above, it looks like the destination account doesn't exist. Make sure that both sender and recipient token accounts are created.
    – john
    Commented Apr 12 at 15:49

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.