2

I need to sign two transactions at once. The first one initialize an AccountLoader, and the second one uses this initialized AccountLoader, therefore the AccountLoader must be initialized once is called the second transaction. I'm using the following code in the client side:

        let allTransactions: Transaction[] = [];
        const tx1 = new Transaction();
        tx1.add(program1.instruction.initializeAccount(
            {
                accounts: {
                    user: userAddress,
                    account: accountAddress, // AccountLoader<'info,zero_copy_account>
                    systemProgram: SystemProgram.programId,
                },
                signers: []
            }
        ));
        allTransactions.push(tx1);

        const tx2 = new Transaction();
        tx2.add(program2.instruction.useAccount(
            {
                accounts: {
                    user: userAddress,
                    account: accountAddress,
                },
                signers: []
            }
        ));
        allTransactions.push(tx2);

        if (wallet.signAllTransactions) {
            const block = await solConnection.getLatestBlockhash();
            allTransactions.forEach(tx => {
                tx.recentBlockhash = block.blockhash;
                tx.feePayer = wallet.publicKey!;
            });

            const signedTransactions = await wallet.signAllTransactions(allTransactions);

            for (const tx of signedTransactions) {
                const txid = await solConnection.sendRawTransaction(
                    tx.serialize(),
                    {
                        skipPreflight: false,
                    }
                );
            }
        }

When I run this code the first transaction is completed successfully, however the second one fails. I think this is because the account is not initialized when the second transaction is being executed.

When I run the @Jon C example both transactions fail. However, if I run the @Jon C example using an account of type Account (not AccountLoader) both transactions are executed successfully. Why does this approach fail when using AccountLoader?

Does anyone know how to complete these two transactions using a single sign?

2
  • Could you include the error that you're seeing?
    – Jon C
    Jan 5, 2023 at 22:17
  • Transaction simulation failed: Error processing Instruction 1: custom program error: 0xbc4 Where can I find the description of this error?
    – cris.sol
    Jan 6, 2023 at 2:12

1 Answer 1

2

As you've noticed, sending two transactions at once that have some dependent state is extremely error-prone, since you can't guarantee the order in which the leader will process the transactions.

If you want to do two things at once, the best option is to do everything in one transaction, ie:

        const tx1 = new Transaction();
        tx1.add(program1.instruction.initializeAccount(
            {
                accounts: {
                    user: userAddress,
                    account: accountAddress, // #[account(init,...
                    systemProgram: SystemProgram.programId,
                },
                signers: []
            }
        ));
        tx1.add(program2.instruction.useAccount(
            {
                accounts: {
                    user: userAddress,
                    account: accountAddress,
                },
                signers: []
            }
        ));

If that isn't possible due to transaction size or compute limit, then you have to send the first transaction, wait for it to confirm, then send the second transaction. I think you'll be able to do the first method in this case though.

3
  • You are right, it is extremely error prone. It has also happened to me that one transaction completes successfully while the other fails and I can't allow that. Do you know if there is a way to specify the order? What you say about doing a transaction first and then checking for success is not possible for me since I have to do it both transactions with a single wallet signature.
    – cris.sol
    Jan 3, 2023 at 14:54
  • In my example of adding two instructions to one transaction, they are guaranteed to be executed in that order, so definitely go with that approach
    – Jon C
    Jan 3, 2023 at 20:00
  • Your example works perfectly if the account that needs to be initialized (account) is of Account type. However, your example doesn't work if the account to be initialized is of AccountLoader type, which is my case.
    – cris.sol
    Jan 5, 2023 at 21:00

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.