1

I get this error

SendTransactionError: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: invalid instruction data at Connection.sendEncodedTransaction (C:\Users\jlavo\node_modules@solana\web3.js\lib\index.cjs.js:8026:13) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async Connection.sendRawTransaction (C:\Users\jlavo\node_modules@solana\web3.js\lib\index.cjs.js:7992:20) at async Connection.sendTransaction (C:\Users\jlavo\node_modules@solana\web3.js\lib\index.cjs.js:7983:12) at async sendAndConfirmTransaction (C:\Users\jlavo\node_modules@solana\web3.js\lib\index.cjs.js:2160:21) at async main (C:\Users\jlavo\Documents\solana-withdrawal\withdrawStake.js:56:26) { logs: [ 'Program Stake11111111111111111111111111111111111111 invoke [1]', 'Program Stake11111111111111111111111111111111111111 failed: invalid instruction data' ] }

In this code

const {
  Connection,
  PublicKey,
  Account,
  SystemProgram,
  sendAndConfirmTransaction,
  Transaction,
  TransactionInstruction,
} = require('@solana/web3.js');

// Function to get user input
async function getUserInput(prompt) {
  const readline = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  return new Promise((resolve) => {
    readline.question(prompt, (answer) => {
      readline.close();
      resolve(answer);
    });
  });
}

// Asynchronous main function
async function main() {
  // Initialize Solana connection for Mainnet
  const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');

  // Prompt user for wallet private key
  const privateKey = await getUserInput('Enter your wallet private key: ');
  const wallet = new Account(Buffer.from(privateKey, 'hex'));

  // Prompt user for stake account public key
  const stakeAccountPublicKeyStr = await getUserInput('Enter your stake account public key: ');
  const stakeAccountPublicKey = new PublicKey(stakeAccountPublicKeyStr);

  // Get recent blockhash
  const blockhash = (await connection.getRecentBlockhash('max')).blockhash;

  // Create a custom stake account deactivation instruction
  const deactivateInstruction = new TransactionInstruction({
    programId: new PublicKey('Stake11111111111111111111111111111111111111'), // Update with the correct StakeProgramId
    keys: [
      { pubkey: wallet.publicKey, isSigner: true, isWritable: true },
      { pubkey: stakeAccountPublicKey, isSigner: false, isWritable: true },
    ],
    data: Buffer.alloc(0), // No additional data required
  });

  // Build a transaction containing the deactivation instruction
  const deactivateTx = new Transaction().add(deactivateInstruction);

  // Sign and send the transaction
  const deactivateTxId = await sendAndConfirmTransaction(connection, deactivateTx, [wallet]);
  console.log(`Stake account deactivated. Tx Id: ${deactivateTxId}`);

  // Prompt user for withdrawal amount
  const withdrawalAmount = await getUserInput('Enter the amount to withdraw (in SOL): ');

  // Withdraw funds from the stake account
  const withdrawTx = SystemProgram.transfer({
    fromPubkey: stakeAccountPublicKey,
    toPubkey: wallet.publicKey,
    lamports: withdrawalAmount * 1e9, // Convert SOL to lamports
  });

  const withdrawTxId = await sendAndConfirmTransaction(connection, withdrawTx, [wallet]);
  console.log(`Stake account withdrawn. Tx Id: ${withdrawTxId}`);

  // Confirm that the stake account balance is now 0
  const stakeBalance = await connection.getBalance(stakeAccountPublicKey);
  console.log(`Stake account balance: ${stakeBalance / 1e9} SOL`);

  // Close the connection or perform any necessary cleanup
  // connection.close(); // Uncomment if needed
}

// Call the asynchronous main function
main().catch((error) => console.error(error));
1
  • Why do you set the instruction data to 0?
    – wei1769
    Commented Jan 22 at 3:03

2 Answers 2

0

There's a few things to fixup here.

First the data for a deactivate instruction is actually [5, 0, 0, 0], given by the index at https://github.com/solana-labs/solana-web3.js/blob/35de86bcc20a751ec4d30bbe0788b402b43f2eb9/packages/library-legacy/src/programs/stake.ts#L538 as a 32-bit unsigned int.

You'll also need to pass in the clock sysvar and reorder the accounts, which gives:

const deactivateInstruction = new TransactionInstruction({
    programId: new PublicKey('Stake11111111111111111111111111111111111111'),
    keys: [
      { pubkey: stakeAccountPublicKey, isSigner: false, isWritable: true },
      { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
      { pubkey: wallet.publicKey, isSigner: true, isWritable: false },
    ],
    data: Buffer.from([5, 0, 0 ,0]),
  });

You'll run into issues later, since you can't immediately withdraw stake from an activate stake account. And to withdraw from a stake account, you must use the StakeProgram.withdraw instruction instead of SystemProgram.transfer. But this should get you started.

And as mentioned in the other answer, it's much easier to just use the bindings at https://github.com/solana-labs/solana-web3.js/blob/35de86bcc20a751ec4d30bbe0788b402b43f2eb9/packages/library-legacy/src/programs/stake.ts#L920

0

You don’t need to build the transaction from scratch, use the method available in the @solana/web3.js package.

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.