Hey there if you are using anchor, you can do cpis in a "anchor way". Also the account that is sending sol either the account is owned by the program(cpi with signer seeds) or needs to be the Signer/Owner.(simple cpi) ( ill show you the both options ) use anchor_lang::{prelude::*, system_program::{Transfer, transfer}}; #[program] mod hello_anchor { use super::*; pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> { ctx.accounts.init(data, &ctx.bumps)?; msg!("Changed data to: {}!", data); } pub fn send_sol(ctx: Context<SendSol>, amount: u64) -> Result<()> { ctx.accounts.send_sol(amount) } pub fn send_sol_pda(ctx: Context<SendSolPda>, amount: u64) -> Result<()> { ctx.accounts.send_sol_pda(amount) } } //Owner Signer way #[derive(Accounts)] pub struct SendSol<'info> { #[account(mut)] pub sender: Signer<'info>, pub receiver: AccountInfo<'info>, pub system_program: Program<'info, System>, } impl<'info> SendSol<'info> { pub fn send_sol( &mut self, amount:u64, ) -> Result<()> { let accounts = Transfer { from: self.sender.to_account_info(), to: self.receiver.to_account_info() }; let ctx = CpiContext::new( self.system_program.to_account_info(), accounts ); transfer(ctx, amount) } } //PDa way #[derive(Accounts)] pub struct SendSolPda<'info> { #[account( seeds=[b"sender"], bump = sender.bump )] pub sender: Account<'info, SigningAccount>, pub receiver: AccountInfo<'info>, pub system_program: Program<'info, System>, } impl<'info> SendSolPda<'info> { pub fn send_sol_pda( &mut self, amount:u64, ) -> Result<()> { let accounts = Transfer { from: self.sender.to_account_info(), to: self.receiver.to_account_info() }; let seeds = &[ &b"sender"[..], &[self.sender.bump], ]; let signer_seeds = &[&seeds[..]]; let ctx = CpiContext::new( self.system_program.to_account_info(), accounts, signer_seeds ); transfer(ctx, amount) } } #[derive(Accounts)] pub struct Initialize<'info> { #[account( init, payer = signer, seeds = [b"sender"], bump, space = SigningAccount::LEN )] pub new_account: Account<'info, SigningAccount>, #[account(mut)] pub signer: Signer<'info>, pub system_program: Program<'info, System>, } impl<'info> Initialize<'info> { pub const LEN: usize = 8 + 8 + 1 pub fn init( &mut self, bumps: &InitializeBumps, data: u64, ) -> Result<()> { self.new_account.set_inner(SigningAccount{ data, bump: bumps.new_account }); Ok(()) } } #[account] pub struct SigningAccount { data: u64, bump: u8, } Notes: 1. Changed your send_sol function; 2. Added send_sol_pda function; 3. Fixed and added the normal cpi way; 4. Added Pda Cpi; 5. Also added a set_inner when initing the type SigningAccount accounts.