@@ -27,12 +27,36 @@ pub mod transfer_sol {
2727 ctx : Context < TransferSolWithProgram > ,
2828 amount : u64 ,
2929 ) -> Result < ( ) > {
30- * * ctx. accounts . payer . try_borrow_mut_lamports ( ) ? -= amount;
31- * * ctx. accounts . recipient . try_borrow_mut_lamports ( ) ? += amount;
30+ // Security invariants:
31+ // - The source account must authorize the transfer (is_signer)
32+ // - The source account must be owned by this program (direct lamports mutation)
33+ // - Prevent under/overflow on lamport arithmetic
34+
35+ let payer_lamports = ctx. accounts . payer . to_account_info ( ) . lamports ( ) ;
36+ require ! ( payer_lamports >= amount, TransferSolError :: InsufficientFunds ) ;
37+
38+ * * ctx. accounts . payer . try_borrow_mut_lamports ( ) ? = payer_lamports
39+ . checked_sub ( amount)
40+ . ok_or ( TransferSolError :: LamportArithmeticOverflow ) ?;
41+
42+ let recipient_lamports = ctx. accounts . recipient . to_account_info ( ) . lamports ( ) ;
43+ * * ctx. accounts . recipient . try_borrow_mut_lamports ( ) ? = recipient_lamports
44+ . checked_add ( amount)
45+ . ok_or ( TransferSolError :: LamportArithmeticOverflow ) ?;
46+
3247 Ok ( ( ) )
3348 }
3449}
3550
51+ #[ error_code]
52+ pub enum TransferSolError {
53+ #[ msg( "Insufficient funds in payer account" ) ]
54+ InsufficientFunds ,
55+
56+ #[ msg( "Lamport arithmetic overflow/underflow" ) ]
57+ LamportArithmeticOverflow ,
58+ }
59+
3660#[ derive( Accounts ) ]
3761pub struct TransferSolWithCpi < ' info > {
3862 #[ account( mut ) ]
@@ -44,12 +68,14 @@ pub struct TransferSolWithCpi<'info> {
4468
4569#[ derive( Accounts ) ]
4670pub struct TransferSolWithProgram < ' info > {
47- /// CHECK: Use owner constraint to check account is owned by our program
71+ // NOTE: This account must sign the transaction, otherwise *anyone* could drain lamports
72+ // from program-owned accounts passed into this instruction.
4873 #[ account(
4974 mut ,
5075 owner = id( ) // value of declare_id!()
5176 ) ]
52- payer : UncheckedAccount < ' info > ,
77+ payer : Signer < ' info > ,
78+
5379 #[ account( mut ) ]
5480 recipient : SystemAccount < ' info > ,
5581}
0 commit comments