0

Program:

#[derive(Accounts)]
pub struct Transact<'info> {
    #[account(init, payer=payer, space= 8 + 1 + 4, seeds=[b"transaction", payer.key.as_ref()], bump)]
    pub transaction: Account<'info, Transaction>,
    
    #[account(mut)]
    pub payer: Signer<'info>,

    pub system_program: Program<'info, System>
}

Test:

//I want to get rid of the client having to  calculate the PDA
const [payerPda, payerPdaBump] = publicKey
  .findProgramAddressSync([anchor.utils.bytes.utf8.encode("transaction"), provider.publicKey.toBuffer()], program.programId);

    await program.methods
          .transact()
          .accounts({
            **transaction: payerPda, //i want to get rid of the need for this**
            payer: provider.publicKey,            
          })
          .rpc();   

Perhaps create another program to do the PDA calculation and send it via CPI?

2
  • 1
    please elaborate (in the description!) your motivation for removing the client-side calculations
    – trent.sol
    Jul 22, 2022 at 21:16
  • The motivation is that I'd like to encapsulate the details of how the program is storing the data and clean up the API so that the client doesn't need to know anything about PDA's or deriving them before calling the program. Jul 22, 2022 at 23:42

2 Answers 2

3

Every account used in a transaction has to be provided by the caller, so this isn't possible in principle. As trent says, if you elaborate on your motivations there might be an alternative way to do what you want.

Edit: I saw your comment. You can definitely write your own SDK code for your program. That's a matter of setting up a typescript project. That's not really my area of most expertise but you could simply do something like

export const myTransact = async (program, provider) => {
    const [payerPda, payerPdaBump] = publicKey.findProgramAddressSync([anchor.utils.bytes.utf8.encode("transaction"), provider.publicKey.toBuffer()], program.programId);

    await program.methods
          .transact()
          .accounts({
            **transaction: payerPda, //i want to get rid of the need for this**
            payer: provider.publicKey,            
          })
          .rpc();  
}

Then let your users import your library and call myTransact(program, provider) . It would be nice if anchor provided this but it doesn't as far as I know.

1

I recently needed to do this and had to do the following:

First, upgraded Anchor to 0.21.0 (or higher). 0.21.0 is the update that allows you to not have to calculate the PDA yourself on the client side.

You can read more about that here https://twitter.com/anchorlang/status/1491906353560006662?s=20&t=ucTjDPOjygOIokPTL0JFuw

Second, in your Anchor.toml file set seeds to true. More on that here https://github.com/coral-xyz/anchor/issues/1004#issuecomment-1020478661

Then you should be able to do the following

await program.methods.transact().rpc();  

No need to pass in the payer either if it's coming from the provider. Here's a repo for reference in case it helps https://github.com/mac1228/solana-token-airdrop/. It uses Anchor 0.24.2.

1
  • Very cool! I was actually hoping to not have to pass it in from the client at all, but anchor doing it behind the scene in the client is as close as we get right now. I'm thinking I can do it with an IPC where the the caller generates the PDA address and passes it to the callee, but I haven't tried yet. Jul 24, 2022 at 4:55

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.