diff --git a/chains/solana/contracts/programs/ccip-router/src/fee_quoter.rs b/chains/solana/contracts/programs/ccip-router/src/fee_quoter.rs index 6e63608f..33a048ca 100644 --- a/chains/solana/contracts/programs/ccip-router/src/fee_quoter.rs +++ b/chains/solana/contracts/programs/ccip-router/src/fee_quoter.rs @@ -90,6 +90,12 @@ pub fn wrap_native_sol<'info>( amount: u64, signer_bump: u8, ) -> Result<()> { + require!( + // guarantee that if caller is a PDA it won't get garbage-collected + *from.owner == System::id() || from.get_lamports() > amount, + CcipRouterError::InsufficientLamports + ); + invoke_signed( &system_instruction::transfer(&from.key(), &to.key(), amount), &[from.to_account_info(), to.to_account_info()], diff --git a/chains/solana/contracts/programs/ccip-router/src/lib.rs b/chains/solana/contracts/programs/ccip-router/src/lib.rs index 753acdb0..6f5484e0 100644 --- a/chains/solana/contracts/programs/ccip-router/src/lib.rs +++ b/chains/solana/contracts/programs/ccip-router/src/lib.rs @@ -1601,6 +1601,8 @@ pub enum CcipRouterError { InvalidTokenPrice, #[msg("Stale gas price")] StaleGasPrice, + #[msg("Insufficient lamports")] + InsufficientLamports, } // TODO: Refactor this to use the same structure as messages: execution_report.validate(..) diff --git a/chains/solana/contracts/target/idl/ccip_router.json b/chains/solana/contracts/target/idl/ccip_router.json index 4ce41f25..ce65621d 100644 --- a/chains/solana/contracts/target/idl/ccip_router.json +++ b/chains/solana/contracts/target/idl/ccip_router.json @@ -2726,6 +2726,9 @@ }, { "name": "StaleGasPrice" + }, + { + "name": "InsufficientLamports" } ] } diff --git a/chains/solana/contracts/tests/ccip/ccip_router_test.go b/chains/solana/contracts/tests/ccip/ccip_router_test.go index 18f696cf..df79eab8 100644 --- a/chains/solana/contracts/tests/ccip/ccip_router_test.go +++ b/chains/solana/contracts/tests/ccip/ccip_router_test.go @@ -2785,7 +2785,7 @@ func TestCCIPRouter(t *testing.T) { } }) - t.Run("hen sending a Valid CCIP Message but the user does not have enough funds of the fee token, it fails", func(t *testing.T) { + t.Run("When sending a Valid CCIP Message but the user does not have enough funds of the fee token, it fails", func(t *testing.T) { message := ccip_router.Solana2AnyMessage{ FeeToken: token2022.mint, Receiver: validReceiverAddress[:], diff --git a/chains/solana/gobindings/ccip_router/types.go b/chains/solana/gobindings/ccip_router/types.go index 4c0ec282..a062a0b8 100644 --- a/chains/solana/gobindings/ccip_router/types.go +++ b/chains/solana/gobindings/ccip_router/types.go @@ -1961,6 +1961,7 @@ const ( InvalidInputsAtaWritable_CcipRouterError InvalidTokenPrice_CcipRouterError StaleGasPrice_CcipRouterError + InsufficientLamports_CcipRouterError ) func (value CcipRouterError) String() string { @@ -2029,6 +2030,8 @@ func (value CcipRouterError) String() string { return "InvalidTokenPrice" case StaleGasPrice_CcipRouterError: return "StaleGasPrice" + case InsufficientLamports_CcipRouterError: + return "InsufficientLamports" default: return "" }