Search code examples
soliditysolanasolana-web3jsphantom-wallet

Debugging "Transaction simulation failed" when sending program instruction (Solana Solidity)


When attempting to make a call to a program compiled with @solana/solidity, I'm getting the following error:

Transaction simulation failed: Error processing Instruction 0: Program failed to complete 
    Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N invoke [1]
    Program log: pxKTQePwHC9MiR52J5AYaRtSLAtkVfcoGS3GaLD24YX
    Program log: sender account missing from transaction
    Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N consumed 200000 of 200000 compute units
    Program failed to complete: BPF program Panicked in solana.c at 285:0
    Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N failed: Program failed to complete

jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N is the program's public key and pxKTQePwHC9MiR52J5AYaRtSLAtkVfcoGS3GaLD24YX is the sender's public key.

I'm using a fork of the @solana/solidity library that exposes the Transaction object so that it can be signed and sent by Phantom Wallet on the front end. The code that results in the error is as follows:

// Generate the transaction
const transaction = contract.transactions.send(...args);

// Add recent blockhash and fee payer
const recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
transaction.recentBlockhash = recentBlockhash;
transaction.feePayer = provider.publicKey;

// Sign and send the transaction (throws an error)
const res = await provider.signAndSendTransaction(transaction);

I would attempt to debug this further myself, but I'm not sure where to start. Looking up the error message hasn't yielded any results and the error message isn't very descriptive. I'm not sure if this error is occurring within the program execution itself or if it's an issue with the composition of the transaction object. If it is an issue within the program execution, is there a way for me to add logs to my solidity code? If it's an issue with the transaction object, what could be missing? How can I better debug issues like this?

Thank you for any help.

Edit: I'm getting a different error now, although I haven't changed any of the provided code. The error message is now the following:

Phantom - RPC Error: Transaction creation failed. {code: -32003, message: 'Transaction creation failed.'}

Unfortunately this error message is even less helpful than the last one. I'm not sure if Phantom Wallet was updated or if a project dependency was updated at some point, but given the vague nature of both of these error messages and the fact that none of my code has changed, I believe they're being caused by the same issue. Again, any help or debugging tips are appreciated.


Solution

  • I was able to solve this issue, and although I've run into another issue it's not related to the contents of this question so I'll post it separately.

    Regarding my edit, I found that the difference between the error messages came down to how I was sending the transaction. At first, I tried sending it with Phantom's .signAndSendTransaction() method, which yielded the second error message (listed under my edit). Then I tried signing & sending the transaction manually, like so:

    const signed = await provider.request({
      method: 'signTransaction',
      params: {
        message: bs58.encode(transaction.serializeMessage()),
      },
    });
    
    const signature = bs58.decode(signed.signature);
    transaction.addSignature(provider.publicKey, signature);
    
    await connection.sendRawTransaction(transaction.serialize())
    

    Which yielded the more verbose error included in my original post. That error message did turn out to be helpful once I realized what to look for -- the sending account's public key was missing from the keys field on the TransactionInstruction on the Transaction. I added it in my fork of the @solana/solidity library and the error went away.

    In short, the way I was able to debug this was by

    1. Using provider.request({ method: 'signTransaction' }) and connection.sendRawTransaction(transaction) rather than Phantom's provider.signAndSendTransaction() method for a more verbose error message
    2. Logging the transaction object and inspecting the instructions closely

    I hope this helps someone else in the future.