2

I'm attempting to transfer SPL tokens using Solana's Web3.js, but I'm encountering a SendTransactionError related to invalid account data during the transaction simulation. I need help understanding and resolving this issue.

const web3 = require('@solana/web3.js');
const splToken = require('@solana/spl-token');
const base58 = require('bs58');

const RPC_URL = "https://api.mainnet-beta.solana.com";
const connection = new web3.Connection(RPC_URL, "confirmed");
const privateKeyFile = 'prvt.txt'; 
const destinationAddress = ''; //adress

async function getTokenAccountInfo(publicKey) {
    try {
        const tokenAccounts = await connection.getParsedTokenAccountsByOwner(publicKey, { programId: splToken.TOKEN_PROGRAM_ID });

        let tokensInfo = [];
        for (const { account } of tokenAccounts.value) {
            const { mint, tokenAmount } = account.data.parsed.info;
            if (tokenAmount.uiAmount > 0) { 
                tokensInfo.push({
                    mint: mint,
                    amount: tokenAmount.uiAmount,
                    decimals: tokenAmount.decimals
                });
            }
        }
        return tokensInfo;
    } catch (error) {
        console.error('Error fetching token accounts:', error);
        return [];
    }
}

async function transferTokens(senderKeypair, mintAddress, destinationPublicKey, amount, decimals) {
    const senderTokenAccount = await splToken.getAssociatedTokenAddress(
        mintAddress,
        senderKeypair.publicKey
    );

    const destinationTokenAccount = await splToken.getAssociatedTokenAddress(
        mintAddress,
        destinationPublicKey
    );

    const roundedAmount = Math.floor(amount * Math.pow(10, decimals));

    const transaction = new web3.Transaction().add(
        splToken.createTransferInstruction(
            senderTokenAccount,
            destinationTokenAccount,
            senderKeypair.publicKey,
            roundedAmount,
            [],
            splToken.TOKEN_PROGRAM_ID
        )
    );

    await web3.sendAndConfirmTransaction(connection, transaction, [senderKeypair]);
}

async function main() {
    const privateKeys = fs.readFileSync(privateKeyFile, 'utf-8').split('\n').filter(line => line.trim().length > 0);
    const destinationPublicKey = new web3.PublicKey(destinationAddress);

    for (const privateKeyBase58 of privateKeys) {
        const privateKeyBytes = base58.decode(privateKeyBase58.trim());
        const senderKeypair = web3.Keypair.fromSecretKey(privateKeyBytes);
        const tokensInfo = await getTokenAccountInfo(senderKeypair.publicKey);

        for (const { mint, amount, decimals } of tokensInfo) {
            const mintPublicKey = new web3.PublicKey(mint);
            await transferTokens(senderKeypair, mintPublicKey, destinationPublicKey, amount, decimals);
            await new Promise(resolve => setTimeout(resolve, 1000)); // delay
        }
    }
}

main();

2 Answers 2

3

my guess is that you have not created your destination Token account. In order to make the transfer the token account needs to be created first if it doesn't yet exist.

You could use getOrCreateAssociatedTokenAccount or createAssociatedTokenAccountInstruction (if you know the account does not already exist) from the @solana/spl-token library. Check out this good discussion here:

Is it possible to make an ATA in one instruction, then use that created ATA in the next instruction, in a single transaction?

1

You haven't created a ATA for the destinationPublicKey for the token.

You could use getOrCreateAssociatedTokenAccount or else

    const tokenATA = getAssociatedTokenAddressSync(mintAddress, destinationPublicKey);
    // Fetches details of the above associated token address
    const check = await connection.getParsedAccountInfo(tokenATA);
    // Creates and initializes the above associated token address if it is not already initialized
    if (check.value == null)
        await createAssociatedTokenAccount(connection, wallet, mintAddress, destinationPublicKey);

This bit of code before the transfer function should solve the issue.

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.