kklas / anchor-client-gen

A tool for generating solana web3 clients from anchor IDLs.
MIT License
135 stars 21 forks source link

How to pass additional `remaining accounts`? #39

Open JoeHowarth opened 2 years ago

JoeHowarth commented 2 years ago

Anchor allows accessing accounts not defined on the Accounts struct through ctx.remaining_accounts. I currently don't see a way to pass these additional accounts in the generated client code cleanly.

Proposal: Add optional arg to pass additional accounts

export function redeem(args: RedeemArgs, accounts: RedeemAccounts, additionalAccounts?: AccountMeta[]) {...}

Haven't tried it yet, but I believe there's a workaround where the returned TransactionInstruction can be mutated, but this is non-ideal

kklas commented 2 years ago

I have thought about this but the reason I didn't add it in is because the remaining accounts aren't in the IDL so there's no way to generate anything useful here.

The way to go is to add them to the returned TransactionInstruction as you mentioned:

const thisInstr = redeem(...)
thisInstr.keys.concat([
      {pubkey: users[0].openOrders, isSigner: false, isWritable: true},
      {pubkey: users[1].openOrders, isSigner: false, isWritable: true},
]);

I would argue that this is cleaner than adding an optional remainingAccounts arg to every instruction method especially since in 99% of the cases you won't use them.

Ultimately you shouldn't have to use resort to remaining accounts but there's a lot of use cases where you have to pass accounts optionally and anchor doesn't support this currently. In fact I would argue that using remaining accounts in your contract is already a workaround. So this should be addressed by adding proper support for optional or variable number of accounts in anchor IMO and then we can generate something useful here. In the meantime adding them to TransactionInstruction seems like a good approach to me.

May I ask why you have to resort to remaining accounts in your contract?

JoeHowarth commented 2 years ago

Yeah that makes sense

I'm writing a cross-chain proxy contract and want to use a single generic instruction to deal with multiple proxied instructions. The alternative is closely coupling the proxy contract to the target contract, which is ok, but not ideal.