Is it possible to use Anchor to transfer SOL from user wallet into another user wallet without actually having to initialize program accounts?

I know someone may think that this can be easily done directly in JavaScript but I need this to be in Rust, to be able to charge fees within an Anchor program.

pub struct PayFees<'info> {
    pub sender: Signer<'info>,
    #[account(mut, constraint = ALLOWED_PUBKEY_OF_THE_RECEIVER == receiver.key())]
    pub receiver: UncheckedAccount<'info>,
    pub system_program: Program<'info, System>,

pub fn pay_fees(ctx: Context<PayFees>) -> Result<()> {
    let fee_transfer_cpi_context = CpiContext::new(
        system_program::Transfer {
            from: ctx.accounts.sender.to_account_info(),
            to: ctx.accounts.receiver.to_account_info(),
    system_program::transfer(fee_transfer_cpi_context, 1_000_000_000)?;

Would it be safe to do something like this? I am not really aware of the risks of using an UncheckedAccount.

2 Answers 2


If you want the recipient to specifically be another user's wallet, you may want to use SystemAccount<'info> instead of UncheckedAccount<'info>. This will assert that the account being provided for that slot is owned by the system program; otherwise, the recipient could be any arbitrary address on the network regardless of owning program (unless you plan on asserting a specific address in the constraints as you have in your example).

The sender also needs to have the mut attribute on it to allow lamport transfers out of the account, but otherwise there isn't anything wrong with this instruction.

I would rethink the need to wrap the system_program::transfer instruction in your own, though, instead of just doing the CPI call from whatever proprietary instruction requires the payment of fees.

  • Why would you rethink the wrapped system_program::transfer? Is it dangerous doing it this way? how can I make a CPI call (I actually thought my approach was using CPI) Commented Oct 13, 2022 at 3:45

I believe fee_transfer_cpi_context amount that you want to transfer. YOu need to write an instruction first. Instruction is an array of data used by smart contracts to complete the transaction. Solana processes this data.

       // transfer_inst type is Instruction
       let transfer_inst=anchor_lang::solana_program::system_instruction::transfer(
            // first arg= from, second arg=to
            // i took those from your code
            // this is amount that you want to send I guess

then you have to invoke this instruction

// invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult

    // from=ctx.accounts.sender.to_account_info()
    // to = ctx.accounts.receiver.to_account_info()
    // from and to are from your code

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.