0

From on-chain program, calling a normal third-party program (without source code, but has IDL) instruction would be like this:

        let accounts_meta = vec![
               // ...   
        ];

        let ix = &solana_program::instruction::Instruction::new_with_bytes(
            target_program.key()                      
            &ix_data,             // Passing instructions through
            accounts_meta, // Just the required account for the other program
        );

        let accounts_info = vec![
              // ...
        ];

        solana_program::program::invoke(
            &ix,
            &accounts_info,
        )?; 

However, now I got a third-party program, who's instruction require caller to pass in some accounts through 'remaining_accounts' parameter.

Info about third-party close-source program:

  1. IDL file is available
  2. They give a JS demo that
    const tx = await xxxProgram.methods
        .xxxMethod({ ...  })
        .accounts({ ...  })
        .remainingAccounts(moreAccountMetas)
        .rpc();

I know well how to pass remaining_accounts if invoke from JS client.

But, I need to call it from my on-chain program, how can I pass this remaining_accounts when do CPI call with solana_program::program::invoke ? Or any other method instead of using invoke?

1 Answer 1

2

Well remaining accounts at the end of the day is just an array of accounts, in anchor lingo context in aCpiContext you specify all the accounts defined in the context and it exposes a helper with_remaining_accounts that consumes CpiContext and returns another CpiContext with the remaining accounts.

If we glance at ToAccountinfos impl for CpiContext it calls accounts impl of to_account_infos and extends the vector with the accounts stored in its with_remaining_field and at the end adds the program id in question.

As far as solana is concerned , solana programs dont have the concept of remaining accounts, they take as input a slice of accounts and depend on the passing program/client/user to ensure the order is correct.

To answer your question , you must make sure the order of accounts you pass to solana::invoke if the recipient program is an anchor program ensure the accounts specified in its Instruction struct are specified first and then pass any remaining accounts you desire and in the end pass the program id, basically mimic what a CpiContext will do, but if you have access to the program crate you can construct a CpiContext from it and then use with_remaining_accounts to pass the additional accounts and bank on anchor to do the rest.

Given you have the idl, you can take a look at this issue : https://github.com/coral-xyz/anchor/pull/2857 which has added the declare_program! macro to generate an on-chain , dependency free module which you can use to interact with this third party program from your onchain program/smart contract.

PSA : the new declare_program feature is not yet released in the distributed anchor versions, you will have to build from source to use it , or you can use this other tool by lads at SaberHq on which the incumbent anchor feature is based on. :https://github.com/saber-hq/anchor-gen

3
  • It is great answer. I woulld prefer to mimic the CpiContext, the work load is acceptable and easy understanding. BTW, do you know by chance the spec of transaction layout ? Commented Mar 29 at 14:55
  • The spec of the taw tx layout ? Basically the serialized raw tx ? Commented Mar 30 at 4:10
  • I mean solana spec, just like the EIPs of Etherumn. Here I want is the one of Tx format . Commented Apr 1 at 4:13

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.