I am trying to create a program that allows the signer user (from) to transfer SOL to a different wallet (to).

For the signer I have the signer object: pub from_user: Signer<'info>,

For the target user I have their PubKey: pub to_user_pubkey: Pubkey

Problem: With the information above I have enough to call

let transfer = system_instruction::transfer(

But for the "program::invoke" I seem to need the AccountInfo for both target and receiver if I look at the documentation.

                to_user_account_info, // If I remove this I get errors

Question: When executing Solana transactions in javascript i only need the Pubkey for the to/target user. Can I make this work in rust too? Or am I forced to store additional information in my Accounts (AccountInfo) about the donation to/target user if I want to mote this transaction to my Rust layer?

It's hard to believe that languages would have different signing constraints...

(For context, in JS you can use SystemProgram.transfer() + connection.confirmTransaction() to do a transaction with Pubkey only)

Appreciating any help on this! <3

UPDATE: After some more fiddling (and the theoretical side from these answers) the code is now working as expected. Thank you so much \o/

Rust side:

pub struct TipSol<'info> {
    pub from: Signer<'info>,
    /// CHECK:` doc comment explaining why no checks through types are necessary.
    pub to: AccountInfo<'info>,
    pub system_program: Program<'info, System>,

JS side:

await program.rpc.tipSol( {
        accounts: {
          from: <public key>,
          to: <public key>,
          systemProgram: SystemProgram.programId,
  • In JS, are you using a wallet from the wallet adapter or similar?
    – sohrab
    Commented Jul 30, 2022 at 1:58
  • this is conflating client with contract code. they are vastly different
    – trent.sol
    Commented Jul 30, 2022 at 3:54

2 Answers 2


I am not sure you can compare those two scenarios:

  • In Rust one, you are in the middle of an on-going transaction, making a CPI call to another program
  • In JS one, you are composing a new transaction and sending it off to the chain

Some background:

A Solana transaction always looks the same once it makes it to the chain. Here is what it looks like (ripped it off my own blog post):

enter image description here

The transaction needs to declare all the accounts upfront and then reference them in the instruction as it needs them.

This does happen on web3.js side but the library handles it for you. A good chunk of Transaction.compileMessage() is dedicated to doing just this.

Solana Rust library is meant to be low-level one so it doesn't offer much developer ergonomics and sometimes it feels like you are repeating yourself.

This is exactly why frameworks like Anchor exist to abstract away some of these inconveniences.


The answer is no, you cannot make this work for Rust as well. You have to use AccountInfo.

However all you need to pass in from the JS client side is a Pubkey. Through Anchor, it'll automatically arrive as AccountInfo in Rust.

  • 1
    Thank you for the clear answer. The tip that anchor is handling the conversion helped alot!
    – baronezz
    Commented Jul 31, 2022 at 11:06

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.