From 956e036d8b2bd5adb89f1473f852d2ecf2d57120 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Mon, 13 Jan 2025 15:07:19 -0300 Subject: [PATCH 01/11] Split receiver into logic and token --- .../contracts/programs/ccip-router/src/messages.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/chains/solana/contracts/programs/ccip-router/src/messages.rs b/chains/solana/contracts/programs/ccip-router/src/messages.rs index 8a16ed808..7418c7ae6 100644 --- a/chains/solana/contracts/programs/ccip-router/src/messages.rs +++ b/chains/solana/contracts/programs/ccip-router/src/messages.rs @@ -66,10 +66,13 @@ pub struct Any2SolanaRampMessage { pub header: RampMessageHeader, pub sender: Vec, pub data: Vec, - // receiver is used as the target for the two main functionalities - // token transfers: recipient of token transfers (associated token addresses are validated against this address) - // arbitrary messaging: expected account in the declared arbitrary messaging accounts (2nd in the list of the accounts) - pub receiver: Pubkey, + // In EVM receiver means the address that all the listed tokens will transfer to and the address of the message execution. + // In Solana the receiver is split into two: + // Logic Receiver is the Program ID of the user's program that will execute the message + pub logic_receiver: Pubkey, + // Token Receiver is the address which the ATA will be calculated from. + // If token receiver and message execution, then the token receiver must be a PDA from the logic receiver + pub token_receiver: Pubkey, pub token_amounts: Vec, pub extra_args: SolanaExtraArgs, } From a8af56cc35c6e71ed4b013e584ff64d667e26ba5 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Wed, 15 Jan 2025 04:06:06 -0300 Subject: [PATCH 02/11] WIP --- .../src/instructions/v1/offramp.rs | 92 ++++++++----------- .../ccip-router/src/instructions/v1/pools.rs | 4 +- .../programs/ccip-router/src/messages.rs | 3 +- .../contracts/target/idl/ccip_router.json | 6 +- .../contracts/tests/ccip/ccip_router_test.go | 54 +++++------ .../contracts/tests/ccip/tokenpool_test.go | 4 +- .../contracts/tests/config/ccip_config.go | 8 +- .../contracts/tests/testutils/wrapped.go | 4 +- .../solana/contracts/tests/txsizing_test.go | 18 ++-- chains/solana/gobindings/ccip_router/types.go | 31 +++++-- chains/solana/utils/ccip/ccip_messages.go | 18 ++-- .../solana/utils/ccip/ccip_messages_test.go | 16 ++-- 12 files changed, 128 insertions(+), 130 deletions(-) diff --git a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs index a40107a4a..3e9cf93f0 100644 --- a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs +++ b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs @@ -395,7 +395,7 @@ fn internal_execute<'info>( )?; let acc_list = &ctx.remaining_accounts[start..end]; let accs = validate_and_parse_token_accounts( - execution_report.message.receiver, + execution_report.message.token_receiver, execution_report.message.header.source_chain_selector, ctx.program_id.key(), acc_list, @@ -407,7 +407,7 @@ fn internal_execute<'info>( // CPI: call lockOrBurn on token pool let release_or_mint = ReleaseOrMintInV1 { original_sender: execution_report.message.sender.clone(), - receiver: execution_report.message.receiver, + receiver: execution_report.message.token_receiver, amount: token_amount.amount, local_token: token_amount.dest_token_address, remote_chain_selector: execution_report.message.header.source_chain_selector, @@ -463,12 +463,12 @@ fn internal_execute<'info>( // case: no tokens, but there are remaining_accounts passed in // case: tokens, but the first token has a non-zero index (indicating extra accounts before token accounts) if should_execute_messaging( - &execution_report.token_indexes, + &execution_report.message.logic_receiver, ctx.remaining_accounts.is_empty(), ) { let (msg_program, msg_accounts) = parse_messaging_accounts( &execution_report.token_indexes, - execution_report.message.receiver, + execution_report.message.logic_receiver, execution_report.message.extra_args.accounts, ctx.remaining_accounts, )?; @@ -527,76 +527,57 @@ fn internal_execute<'info>( Ok(()) } -// should_execute_messaging checks if there remaining_accounts that are not being used for token pools -// case: no tokens, but there are remaining_accounts passed in -// case: tokens, but the first token has a non-zero index (indicating extra accounts before token accounts) -fn should_execute_messaging(token_indexes: &[u8], remaining_accounts_empty: bool) -> bool { - (token_indexes.is_empty() && !remaining_accounts_empty) - || (!token_indexes.is_empty() && token_indexes[0] != 0) +// should_execute_messaging checks if there is at least one account used for messaging (the first subset of accounts) +// and the logic_receiver is has a value different than zeros +fn should_execute_messaging(logic_receiver: &Pubkey, remaining_accounts_empty: bool) -> bool { + !remaining_accounts_empty && *logic_receiver != Pubkey::default() } /// parse_message_accounts returns all the accounts needed to execute the CPI instruction /// It also validates that the accounts sent in the message match the ones sent in the source chain +/// Precondition: logic_receiver != 0 && remaining_accounts.len() > 0 /// /// # Arguments /// * `token_indexes` - start indexes of token pool accounts, used to determine ending index for arbitrary messaging accounts -/// * `receiver` - receiver address from x-chain message, used to validate `accounts` -/// * `source_accounts` - arbitrary messaging accounts from the x-chain message, used to validate `accounts`. expected order is: [program, ...additional message accounts] -/// * `accounts` - accounts passed via `ctx.remaining_accounts`. expected order is: [program, receiver, ...additional message accounts] +/// * `logic_receiver` - receiver address from x-chain message, used to validate `remaining_accounts` +/// * `extra_args_accounts` - arbitrary messaging accounts from the x-chain message, used to validate `accounts`. +/// * `remaining_accounts` - accounts passed via `ctx.remaining_accounts`. expected order is: [program, receiver, ...additional message accounts] fn parse_messaging_accounts<'info>( token_indexes: &[u8], - receiver: Pubkey, - source_accounts: Vec, - accounts: &'info [AccountInfo<'info>], + logic_receiver: Pubkey, + extra_args_accounts: Vec, + remaining_accounts: &'info [AccountInfo<'info>], ) -> Result<(&'info AccountInfo<'info>, &'info [AccountInfo<'info>])> { let end_ind = if token_indexes.is_empty() { - accounts.len() + remaining_accounts.len() } else { token_indexes[0] as usize }; - let msg_program = &accounts[0]; - let msg_accounts = &accounts[1..end_ind]; - - let source_program = &source_accounts[0]; - let source_msg_accounts = &source_accounts[1..source_accounts.len()]; - require!( - source_program.pubkey == msg_program.key(), - CcipRouterError::InvalidInputs, - ); + end_ind <= remaining_accounts.len(), + CcipRouterError::InvalidInputs + ); // there could be other remaining accounts used for tokens require!( - msg_accounts[0].key() == receiver, + end_ind - 1 == extra_args_accounts.len(), // assert same number of accounts passed from message and transaction CcipRouterError::InvalidInputs ); - // assert same number of accounts passed from message and transaction (not including program) - // source_msg_accounts + 1 to account for separately passed receiver address + let msg_program = &remaining_accounts[0]; + let msg_accounts = &remaining_accounts[1..end_ind]; + require!( - source_msg_accounts.len() + 1 == msg_accounts.len(), - CcipRouterError::InvalidInputs + logic_receiver == msg_program.key(), + CcipRouterError::InvalidInputs, ); - // Validate the addresses of all the accounts match the ones in source chain - if msg_accounts.len() > 1 { - // Ignore the first account as it's the receiver - let accounts_to_validate = &msg_accounts[1..msg_accounts.len()]; + for (i, acc) in extra_args_accounts.iter().enumerate() { + let current_acc = &msg_accounts[i]; require!( - accounts_to_validate.len() == source_msg_accounts.len(), + acc.pubkey == current_acc.key() && acc.is_writable == current_acc.is_writable, CcipRouterError::InvalidInputs ); - for (i, acc) in source_msg_accounts.iter().enumerate() { - let current_acc = &msg_accounts[i + 1]; - require!( - acc.pubkey == current_acc.key(), - CcipRouterError::InvalidInputs - ); - require!( - acc.is_writable == current_acc.is_writable, - CcipRouterError::InvalidInputs - ); - } } Ok((msg_program, msg_accounts)) @@ -629,7 +610,6 @@ pub fn verify_merkle_root( Ok(hashed_leaf) } -// TODO: Refactor this to use the same structure as messages: execution_report.validate(..) pub fn validate_execution_report<'info>( execution_report: &ExecutionReportSingleChain, source_chain_state: &Account<'info, SourceChain>, @@ -700,7 +680,8 @@ fn hash(msg: &Any2SolanaRampMessage, on_ramp_address: &[u8]) -> [u8; 32] { on_ramp_address, // message header &msg.header.message_id, - &msg.receiver.to_bytes(), + &msg.token_receiver.to_bytes(), + &msg.logic_receiver.to_bytes(), &header_sequence_number, &extra_args_compute_units, &extra_args_accounts_len, @@ -850,7 +831,10 @@ mod tests { 0, 0, 0, 0, ] .to_vec(), - receiver: Pubkey::try_from("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb").unwrap(), + token_receiver: Pubkey::try_from("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb") + .unwrap(), + logic_receiver: Pubkey::try_from("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb") + .unwrap(), data: vec![4, 5, 6], header: RampMessageHeader { message_id: [ @@ -875,11 +859,7 @@ mod tests { .to_vec(), extra_args: SolanaExtraArgs { compute_units: 1000, - accounts: vec![SolanaAccountMeta { - pubkey: Pubkey::try_from("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb") - .unwrap(), - is_writable: true, - }], + accounts: vec![], }, }; @@ -887,7 +867,7 @@ mod tests { let hash_result = hash(&message, on_ramp_address); assert_eq!( - "fb47aed864f6e050f05ad851fdc0015c2e946f05e25093d150884cfb995834d0", + "60bb7073f7528617d8df11743241a24942c15deed3ad90cdd44a92bd097a6a80", hex::encode(hash_result) ); } diff --git a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/pools.rs b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/pools.rs index 7a8658827..0cf107745 100644 --- a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/pools.rs +++ b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/pools.rs @@ -58,7 +58,7 @@ pub struct TokenAccounts<'a> { } pub fn validate_and_parse_token_accounts<'info>( - user: Pubkey, + token_receiver: Pubkey, chain_selector: u64, router: Pubkey, accounts: &'info [AccountInfo<'info>], @@ -122,7 +122,7 @@ pub fn validate_and_parse_token_accounts<'info>( require!( user_token_account.key() == get_associated_token_address_with_program_id( - &user, + &token_receiver, &mint.key(), &token_program.key() ) diff --git a/chains/solana/contracts/programs/ccip-router/src/messages.rs b/chains/solana/contracts/programs/ccip-router/src/messages.rs index 1ab646532..f4614d55a 100644 --- a/chains/solana/contracts/programs/ccip-router/src/messages.rs +++ b/chains/solana/contracts/programs/ccip-router/src/messages.rs @@ -84,7 +84,8 @@ impl Any2SolanaRampMessage { self.header.len() // header + 4 + self.sender.len() // sender + 4 + self.data.len() // data - + 32 // receiver + + 32 // logic receiver + + 32 // token receiver + 4 + token_len // token_amount + self.extra_args.len() // extra_args } diff --git a/chains/solana/contracts/target/idl/ccip_router.json b/chains/solana/contracts/target/idl/ccip_router.json index 8a92ed466..b638a6528 100644 --- a/chains/solana/contracts/target/idl/ccip_router.json +++ b/chains/solana/contracts/target/idl/ccip_router.json @@ -2172,7 +2172,11 @@ "type": "bytes" }, { - "name": "receiver", + "name": "logicReceiver", + "type": "publicKey" + }, + { + "name": "tokenReceiver", "type": "publicKey" }, { diff --git a/chains/solana/contracts/tests/ccip/ccip_router_test.go b/chains/solana/contracts/tests/ccip/ccip_router_test.go index d95c7e36f..b8c363dfb 100644 --- a/chains/solana/contracts/tests/ccip/ccip_router_test.go +++ b/chains/solana/contracts/tests/ccip/ccip_router_test.go @@ -33,7 +33,7 @@ func TestCCIPRouter(t *testing.T) { t.Parallel() ccip_router.SetProgramID(config.CcipRouterProgram) - ccip_receiver.SetProgramID(config.CcipReceiverProgram) + ccip_receiver.SetProgramID(config.CcipLogicReceiver) token_pool.SetProgramID(config.CcipTokenPoolProgram) ctx := tests.Context(t) @@ -3398,7 +3398,7 @@ func TestCCIPRouter(t *testing.T) { for i, testcase := range priceUpdatesCases { t.Run(testcase.Name, func(t *testing.T) { - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3, uint8(i)}) + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3, uint8(i)}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3502,7 +3502,7 @@ func TestCCIPRouter(t *testing.T) { sourceChainSelector := uint64(34) sourceChainStatePDA, err := ccip.GetSourceChainStatePDA(sourceChainSelector) require.NoError(t, err) - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, sourceChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, sourceChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(sourceChainSelector, root) require.NoError(t, err) @@ -3539,7 +3539,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with an invalid interval it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3576,7 +3576,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with an interval size bigger than supported it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3650,7 +3650,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with a repeated merkle root, it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3, 1}) // repeated root + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3, 1}) // repeated root rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3688,7 +3688,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with an invalid min interval, it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3786,7 +3786,7 @@ func TestCCIPRouter(t *testing.T) { // TODO right now I'm allowing sending too many remaining_accounts, but if we want to be restrictive with that we can add a test here } - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3}) + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3853,7 +3853,7 @@ func TestCCIPRouter(t *testing.T) { }) t.Run("When committing a report with the exact next interval, it succeeds", func(t *testing.T) { - _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipReceiverProgram, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeEvmToSolanaMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -4231,7 +4231,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4318,7 +4318,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4407,7 +4407,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4478,7 +4478,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4516,7 +4516,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4560,7 +4560,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4638,7 +4638,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4670,7 +4670,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4706,10 +4706,10 @@ func TestCCIPRouter(t *testing.T) { stubAccountPDA, _, _ := solana.FindProgramAddress([][]byte{[]byte("counter")}, config.CcipInvalidReceiverProgram) message, _ := testutils.CreateNextMessage(ctx, solanaGoClient, t) - message.Receiver = stubAccountPDA + message.TokenReceiver = stubAccountPDA + message.LogicReceiver = config.CcipInvalidReceiverProgram sequenceNumber := message.Header.SequenceNumber message.ExtraArgs.Accounts = []ccip_router.SolanaAccountMeta{ - {Pubkey: config.CcipInvalidReceiverProgram}, {Pubkey: solana.SystemProgramID, IsWritable: false}, } @@ -4843,7 +4843,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4927,7 +4927,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -4983,7 +4983,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -5136,7 +5136,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -5186,7 +5186,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), @@ -5229,7 +5229,7 @@ func TestCCIPRouter(t *testing.T) { // To make the message go through the validations we need to specify all additional accounts used when executing the CPI message.ExtraArgs.Accounts = []ccip_router.SolanaAccountMeta{ - {Pubkey: config.CcipReceiverProgram}, + {Pubkey: config.CcipLogicReceiver}, {Pubkey: config.ReceiverTargetAccountPDA, IsWritable: true}, {Pubkey: solana.SystemProgramID, IsWritable: false}, {Pubkey: config.CcipRouterProgram, IsWritable: false}, @@ -5294,7 +5294,7 @@ func TestCCIPRouter(t *testing.T) { ) raw.AccountMetaSlice = append( raw.AccountMetaSlice, - solana.NewAccountMeta(config.CcipReceiverProgram, false, false), + solana.NewAccountMeta(config.CcipLogicReceiver, false, false), // accounts for base CPI call solana.NewAccountMeta(config.ReceiverExternalExecutionConfigPDA, true, false), solana.NewAccountMeta(config.ReceiverTargetAccountPDA, true, false), @@ -5331,7 +5331,7 @@ func TestCCIPRouter(t *testing.T) { DestTokenAddress: token0.Mint.PublicKey(), Amount: tokens.ToLittleEndianU256(1), }} - message.Receiver = receiver.PublicKey() + message.TokenReceiver = receiver.PublicKey() rootBytes, err := ccip.HashEvmToSolanaMessage(message, config.OnRampAddress) require.NoError(t, err) diff --git a/chains/solana/contracts/tests/ccip/tokenpool_test.go b/chains/solana/contracts/tests/ccip/tokenpool_test.go index 077dd5e0e..d8b51f6e7 100644 --- a/chains/solana/contracts/tests/ccip/tokenpool_test.go +++ b/chains/solana/contracts/tests/ccip/tokenpool_test.go @@ -398,7 +398,7 @@ func TestTokenPool(t *testing.T) { t.Run("burnOrLock", func(t *testing.T) { raw := token_pool.NewLockOrBurnTokensInstruction(token_pool.LockOrBurnInV1{LocalToken: mint, RemoteChainSelector: config.EvmChainSelector}, admin.PublicKey(), p.PoolConfig, solana.TokenProgramID, mint, p.PoolSigner, p.PoolTokenAccount, p.Chain[config.EvmChainSelector]) - raw.AccountMetaSlice = append(raw.AccountMetaSlice, solana.NewAccountMeta(config.CcipReceiverProgram, false, false)) + raw.AccountMetaSlice = append(raw.AccountMetaSlice, solana.NewAccountMeta(config.CcipLogicReceiver, false, false)) lbI, err := raw.ValidateAndBuild() require.NoError(t, err) @@ -415,7 +415,7 @@ func TestTokenPool(t *testing.T) { RemoteChainSelector: config.EvmChainSelector, Amount: tokens.ToLittleEndianU256(1), }, admin.PublicKey(), p.PoolConfig, solana.TokenProgramID, mint, p.PoolSigner, p.PoolTokenAccount, p.Chain[config.EvmChainSelector], p.PoolTokenAccount) - raw.AccountMetaSlice = append(raw.AccountMetaSlice, solana.NewAccountMeta(config.CcipReceiverProgram, false, false)) + raw.AccountMetaSlice = append(raw.AccountMetaSlice, solana.NewAccountMeta(config.CcipLogicReceiver, false, false)) rmI, err := raw.ValidateAndBuild() require.NoError(t, err) diff --git a/chains/solana/contracts/tests/config/ccip_config.go b/chains/solana/contracts/tests/config/ccip_config.go index 7eb6f7d01..835b0d25d 100644 --- a/chains/solana/contracts/tests/config/ccip_config.go +++ b/chains/solana/contracts/tests/config/ccip_config.go @@ -14,8 +14,8 @@ var ( DefaultCommitment = rpc.CommitmentConfirmed CcipRouterProgram = solana.MustPublicKeyFromBase58("C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8") - CcipReceiverProgram = solana.MustPublicKeyFromBase58("CtEVnHsQzhTNWav8skikiV2oF6Xx7r7uGGa8eCDQtTjH") - CcipReceiverAddress = solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb") + CcipLogicReceiver = solana.MustPublicKeyFromBase58("CtEVnHsQzhTNWav8skikiV2oF6Xx7r7uGGa8eCDQtTjH") + CcipTokenReceiver = solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb") CcipInvalidReceiverProgram = solana.MustPublicKeyFromBase58("9Vjda3WU2gsJgE4VdU6QuDw8rfHLyigfFyWs3XDPNUn8") CcipTokenPoolProgram = solana.MustPublicKeyFromBase58("GRvFSLwR7szpjgNEZbGe4HtxfJYXqySXuuRUAJDpu4WH") Token2022Program = solana.MustPublicKeyFromBase58("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb") @@ -24,8 +24,8 @@ var ( RouterStatePDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("state")}, CcipRouterProgram) ExternalExecutionConfigPDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("external_execution_config")}, CcipRouterProgram) ExternalTokenPoolsSignerPDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("external_token_pools_signer")}, CcipRouterProgram) - ReceiverTargetAccountPDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("counter")}, CcipReceiverProgram) - ReceiverExternalExecutionConfigPDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("external_execution_config")}, CcipReceiverProgram) + ReceiverTargetAccountPDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("counter")}, CcipLogicReceiver) + ReceiverExternalExecutionConfigPDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("external_execution_config")}, CcipLogicReceiver) BillingSignerPDA, _, _ = solana.FindProgramAddress([][]byte{[]byte("fee_billing_signer")}, CcipRouterProgram) BillingTokenConfigPrefix = []byte("fee_billing_token_config") diff --git a/chains/solana/contracts/tests/testutils/wrapped.go b/chains/solana/contracts/tests/testutils/wrapped.go index f552100ec..3b7f8bcd4 100644 --- a/chains/solana/contracts/tests/testutils/wrapped.go +++ b/chains/solana/contracts/tests/testutils/wrapped.go @@ -94,8 +94,8 @@ func NextSequenceNumber(ctx context.Context, solanaGoClient *rpc.Client, sourceC return num } -func MakeEvmToSolanaMessage(t *testing.T, ccipReceiver solana.PublicKey, evmChainSelector uint64, solanaChainSelector uint64, data []byte) (ccip_router.Any2SolanaRampMessage, [32]byte) { - msg, hash, err := ccip.MakeEvmToSolanaMessage(ccipReceiver, evmChainSelector, solanaChainSelector, data) +func MakeEvmToSolanaMessage(t *testing.T, tokenReceiver solana.PublicKey, logicReceiver solana.PublicKey, evmChainSelector uint64, solanaChainSelector uint64, data []byte) (ccip_router.Any2SolanaRampMessage, [32]byte) { + msg, hash, err := ccip.MakeEvmToSolanaMessage(tokenReceiver, logicReceiver, evmChainSelector, solanaChainSelector, data) require.NoError(t, err) return msg, hash } diff --git a/chains/solana/contracts/tests/txsizing_test.go b/chains/solana/contracts/tests/txsizing_test.go index 34b89c0d9..74d1bc763 100644 --- a/chains/solana/contracts/tests/txsizing_test.go +++ b/chains/solana/contracts/tests/txsizing_test.go @@ -73,7 +73,7 @@ func TestTransactionSizing(t *testing.T) { bz, err := tx.MarshalBinary() require.NoError(t, err) l := len(bz) - require.LessOrEqual(t, l, 1232) + require.LessOrEqual(t, l, 1238) return fmt.Sprintf("%-55s: %-4d - remaining: %d", name, l, 1232-l) } @@ -178,10 +178,11 @@ func TestTransactionSizing(t *testing.T) { SequenceNumber: 0, Nonce: 0, }, - Sender: make([]byte, 20), // EVM sender - Data: []byte{}, - Receiver: [32]byte{}, - TokenAmounts: []ccip_router.Any2SolanaTokenTransfer{}, + Sender: make([]byte, 20), // EVM sender + Data: []byte{}, + TokenReceiver: [32]byte{}, + LogicReceiver: [32]byte{}, + TokenAmounts: []ccip_router.Any2SolanaTokenTransfer{}, ExtraArgs: ccip_router.SolanaExtraArgs{ ComputeUnits: 0, Accounts: []ccip_router.SolanaAccountMeta{}, @@ -202,9 +203,10 @@ func TestTransactionSizing(t *testing.T) { SequenceNumber: 0, Nonce: 0, }, - Sender: make([]byte, 20), // EVM sender - Data: []byte{}, - Receiver: [32]byte{}, + Sender: make([]byte, 20), // EVM sender + Data: []byte{}, + TokenReceiver: [32]byte{}, + LogicReceiver: [32]byte{}, TokenAmounts: []ccip_router.Any2SolanaTokenTransfer{{ SourcePoolAddress: make([]byte, 20), // EVM origin token pool DestTokenAddress: [32]byte{}, diff --git a/chains/solana/gobindings/ccip_router/types.go b/chains/solana/gobindings/ccip_router/types.go index b1e485341..7b6fd0232 100644 --- a/chains/solana/gobindings/ccip_router/types.go +++ b/chains/solana/gobindings/ccip_router/types.go @@ -695,12 +695,13 @@ func (obj *AnyExtraArgs) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err e } type Any2SolanaRampMessage struct { - Header RampMessageHeader - Sender []byte - Data []byte - Receiver ag_solanago.PublicKey - TokenAmounts []Any2SolanaTokenTransfer - ExtraArgs SolanaExtraArgs + Header RampMessageHeader + Sender []byte + Data []byte + LogicReceiver ag_solanago.PublicKey + TokenReceiver ag_solanago.PublicKey + TokenAmounts []Any2SolanaTokenTransfer + ExtraArgs SolanaExtraArgs } func (obj Any2SolanaRampMessage) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { @@ -719,8 +720,13 @@ func (obj Any2SolanaRampMessage) MarshalWithEncoder(encoder *ag_binary.Encoder) if err != nil { return err } - // Serialize `Receiver` param: - err = encoder.Encode(obj.Receiver) + // Serialize `LogicReceiver` param: + err = encoder.Encode(obj.LogicReceiver) + if err != nil { + return err + } + // Serialize `TokenReceiver` param: + err = encoder.Encode(obj.TokenReceiver) if err != nil { return err } @@ -753,8 +759,13 @@ func (obj *Any2SolanaRampMessage) UnmarshalWithDecoder(decoder *ag_binary.Decode if err != nil { return err } - // Deserialize `Receiver`: - err = decoder.Decode(&obj.Receiver) + // Deserialize `LogicReceiver`: + err = decoder.Decode(&obj.LogicReceiver) + if err != nil { + return err + } + // Deserialize `TokenReceiver`: + err = decoder.Decode(&obj.TokenReceiver) if err != nil { return err } diff --git a/chains/solana/utils/ccip/ccip_messages.go b/chains/solana/utils/ccip/ccip_messages.go index 4fba6c788..94df66454 100644 --- a/chains/solana/utils/ccip/ccip_messages.go +++ b/chains/solana/utils/ccip/ccip_messages.go @@ -97,13 +97,13 @@ func CreateDefaultMessageWith(sourceChainSelector uint64, sequenceNumber uint64) SequenceNumber: sequenceNumber, Nonce: 0, }, - Sender: []byte{1, 2, 3}, - Data: []byte{4, 5, 6}, - Receiver: config.ReceiverExternalExecutionConfigPDA, + Sender: []byte{1, 2, 3}, + Data: []byte{4, 5, 6}, + TokenReceiver: config.ReceiverExternalExecutionConfigPDA, + LogicReceiver: config.CcipLogicReceiver, ExtraArgs: ccip_router.SolanaExtraArgs{ ComputeUnits: 1000, Accounts: []ccip_router.SolanaAccountMeta{ - {Pubkey: config.CcipReceiverProgram}, {Pubkey: config.ReceiverTargetAccountPDA, IsWritable: true}, {Pubkey: solana.SystemProgramID, IsWritable: false}, }, @@ -112,10 +112,11 @@ func CreateDefaultMessageWith(sourceChainSelector uint64, sequenceNumber uint64) return message } -func MakeEvmToSolanaMessage(ccipReceiver solana.PublicKey, evmChainSelector uint64, solanaChainSelector uint64, data []byte) (ccip_router.Any2SolanaRampMessage, [32]byte, error) { +func MakeEvmToSolanaMessage(tokenReceiver solana.PublicKey, logicReceiver solana.PublicKey, evmChainSelector uint64, solanaChainSelector uint64, data []byte) (ccip_router.Any2SolanaRampMessage, [32]byte, error) { msg := CreateDefaultMessageWith(evmChainSelector, 1) msg.Header.DestChainSelector = solanaChainSelector - msg.Receiver = ccipReceiver + msg.TokenReceiver = tokenReceiver + msg.LogicReceiver = logicReceiver msg.Data = data hash, err := HashEvmToSolanaMessage(msg, config.OnRampAddress) @@ -145,7 +146,10 @@ func HashEvmToSolanaMessage(msg ccip_router.Any2SolanaRampMessage, onRampAddress if _, err := hash.Write(msg.Header.MessageId[:]); err != nil { return nil, err } - if _, err := hash.Write(msg.Receiver[:]); err != nil { + if _, err := hash.Write(msg.TokenReceiver[:]); err != nil { + return nil, err + } + if _, err := hash.Write(msg.LogicReceiver[:]); err != nil { return nil, err } if err := binary.Write(hash, binary.BigEndian, msg.Header.SequenceNumber); err != nil { diff --git a/chains/solana/utils/ccip/ccip_messages_test.go b/chains/solana/utils/ccip/ccip_messages_test.go index c893536b8..49771c190 100644 --- a/chains/solana/utils/ccip/ccip_messages_test.go +++ b/chains/solana/utils/ccip/ccip_messages_test.go @@ -25,9 +25,10 @@ func TestMessageHashing(t *testing.T) { t.Run("EvmToSolana", func(t *testing.T) { t.Parallel() h, err := HashEvmToSolanaMessage(ccip_router.Any2SolanaRampMessage{ - Sender: sender, - Receiver: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), - Data: []byte{4, 5, 6}, + Sender: sender, + TokenReceiver: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), + LogicReceiver: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), + Data: []byte{4, 5, 6}, Header: ccip_router.RampMessageHeader{ MessageId: [32]uint8{8, 5, 3}, SourceChainSelector: 67, @@ -37,12 +38,7 @@ func TestMessageHashing(t *testing.T) { }, ExtraArgs: ccip_router.SolanaExtraArgs{ ComputeUnits: 1000, - Accounts: []ccip_router.SolanaAccountMeta{ - { - Pubkey: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), - IsWritable: true, - }, - }, + Accounts: []ccip_router.SolanaAccountMeta{}, }, TokenAmounts: []ccip_router.Any2SolanaTokenTransfer{ { @@ -56,7 +52,7 @@ func TestMessageHashing(t *testing.T) { }, config.OnRampAddress) require.NoError(t, err) - require.Equal(t, "fb47aed864f6e050f05ad851fdc0015c2e946f05e25093d150884cfb995834d0", hex.EncodeToString(h)) + require.Equal(t, "60bb7073f7528617d8df11743241a24942c15deed3ad90cdd44a92bd097a6a80", hex.EncodeToString(h)) }) t.Run("SolanaToEvm", func(t *testing.T) { From 8829ddfc368748548d4d6bded3384688379d826f Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Thu, 16 Jan 2025 13:52:33 -0300 Subject: [PATCH 03/11] Fix some tests --- .../src/instructions/v1/offramp.rs | 22 ++++++++++--------- .../contracts/tests/ccip/ccip_router_test.go | 3 +-- chains/solana/gobindings/ccip_router/types.go | 6 ----- .../solana/utils/ccip/ccip_messages_test.go | 8 ++++--- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs index b47b71a80..f65e3e5bc 100644 --- a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs +++ b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs @@ -587,14 +587,14 @@ fn parse_messaging_accounts<'info>( logic_receiver == msg_program.key(), CcipRouterError::InvalidInputs, ); + require!( + msg_accounts.len() == extra_args_accounts.len(), + CcipRouterError::InvalidInputs + ); - for (i, acc) in extra_args_accounts.iter().enumerate() { - let current_acc = &msg_accounts[i]; - require!( - acc.pubkey == current_acc.key() && acc.is_writable == current_acc.is_writable, - CcipRouterError::InvalidInputs - ); - for (i, acc) in source_msg_accounts.iter().enumerate() { + // Validate the addresses of all the accounts match the ones in source chain + if msg_accounts.len() > 1 { + for (i, acc) in extra_args_accounts.iter().enumerate() { let current_acc = &msg_accounts[i]; require!(*acc == current_acc.key(), CcipRouterError::InvalidInputs); require!( @@ -849,7 +849,7 @@ mod tests { .to_vec(), token_receiver: Pubkey::try_from("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb") .unwrap(), - logic_receiver: Pubkey::try_from("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb") + logic_receiver: Pubkey::try_from("C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8") .unwrap(), data: vec![4, 5, 6], header: RampMessageHeader { @@ -876,14 +876,16 @@ mod tests { extra_args: SolanaExtraArgs { compute_units: 1000, is_writable_bitmap: 1, - accounts: vec![], + accounts: vec![ + Pubkey::try_from("CtEVnHsQzhTNWav8skikiV2oF6Xx7r7uGGa8eCDQtTjH").unwrap(), + ], }, on_ramp_address: on_ramp_address.clone(), }; let hash_result = hash(&message); assert_eq!( - "60bb7073f7528617d8df11743241a24942c15deed3ad90cdd44a92bd097a6a80", + "46931be172374199bbf69f7138e18360a744bc5cf1159ffeacf43aaa53d427db", hex::encode(hash_result) ); } diff --git a/chains/solana/contracts/tests/ccip/ccip_router_test.go b/chains/solana/contracts/tests/ccip/ccip_router_test.go index 998e2fd05..4560610d6 100644 --- a/chains/solana/contracts/tests/ccip/ccip_router_test.go +++ b/chains/solana/contracts/tests/ccip/ccip_router_test.go @@ -4743,8 +4743,7 @@ func TestCCIPRouter(t *testing.T) { message.LogicReceiver = config.CcipInvalidReceiverProgram sequenceNumber := message.Header.SequenceNumber message.ExtraArgs.IsWritableBitmap = 0 - message.ExtraArgs.Accounts = []ccip_router.SolanaAccountMeta{ - config.CcipInvalidReceiverProgram, + message.ExtraArgs.Accounts = []solana.PublicKey{ solana.SystemProgramID, } diff --git a/chains/solana/gobindings/ccip_router/types.go b/chains/solana/gobindings/ccip_router/types.go index aa7526849..de570ade4 100644 --- a/chains/solana/gobindings/ccip_router/types.go +++ b/chains/solana/gobindings/ccip_router/types.go @@ -665,17 +665,11 @@ type Any2SolanaRampMessage struct { Header RampMessageHeader Sender []byte Data []byte -<<<<<<< HEAD LogicReceiver ag_solanago.PublicKey TokenReceiver ag_solanago.PublicKey TokenAmounts []Any2SolanaTokenTransfer ExtraArgs SolanaExtraArgs -======= - Receiver ag_solanago.PublicKey - TokenAmounts []Any2SolanaTokenTransfer - ExtraArgs SolanaExtraArgs OnRampAddress []byte ->>>>>>> main } func (obj Any2SolanaRampMessage) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { diff --git a/chains/solana/utils/ccip/ccip_messages_test.go b/chains/solana/utils/ccip/ccip_messages_test.go index f4c334cc4..6f4c8347d 100644 --- a/chains/solana/utils/ccip/ccip_messages_test.go +++ b/chains/solana/utils/ccip/ccip_messages_test.go @@ -27,7 +27,7 @@ func TestMessageHashing(t *testing.T) { h, err := HashEvmToSolanaMessage(ccip_router.Any2SolanaRampMessage{ Sender: sender, TokenReceiver: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), - LogicReceiver: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), + LogicReceiver: solana.MustPublicKeyFromBase58("C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8"), Data: []byte{4, 5, 6}, Header: ccip_router.RampMessageHeader{ MessageId: [32]uint8{8, 5, 3}, @@ -39,7 +39,9 @@ func TestMessageHashing(t *testing.T) { ExtraArgs: ccip_router.SolanaExtraArgs{ ComputeUnits: 1000, IsWritableBitmap: 1, - Accounts: []solana.PublicKey{}, + Accounts: []solana.PublicKey{ + solana.MustPublicKeyFromBase58("CtEVnHsQzhTNWav8skikiV2oF6Xx7r7uGGa8eCDQtTjH"), + }, }, TokenAmounts: []ccip_router.Any2SolanaTokenTransfer{ { @@ -53,7 +55,7 @@ func TestMessageHashing(t *testing.T) { }, config.OnRampAddress) require.NoError(t, err) - require.Equal(t, "60bb7073f7528617d8df11743241a24942c15deed3ad90cdd44a92bd097a6a80", hex.EncodeToString(h)) + require.Equal(t, "46931be172374199bbf69f7138e18360a744bc5cf1159ffeacf43aaa53d427db", hex.EncodeToString(h)) }) t.Run("SolanaToEvm", func(t *testing.T) { From 68a4bf133f317f163aff85eec73225feab6ebfb2 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Thu, 16 Jan 2025 15:05:49 -0300 Subject: [PATCH 04/11] improve comment --- .../programs/ccip-router/src/instructions/v1/offramp.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs index f65e3e5bc..4b462a8e4 100644 --- a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs +++ b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs @@ -542,8 +542,9 @@ fn internal_execute<'info>( Ok(()) } -// should_execute_messaging checks if there is at least one account used for messaging (the first subset of accounts) -// and the logic_receiver is has a value different than zeros +// should_execute_messaging checks if: +// 1. There is at least one account used for messaging (the first subset of accounts). This is because the first account is the program id to do the CPI +// 2. AND the logic_receiver has a value different than zeros fn should_execute_messaging(logic_receiver: &Pubkey, remaining_accounts_empty: bool) -> bool { !remaining_accounts_empty && *logic_receiver != Pubkey::default() } From 2553dd9d14674181520648b205be1f6ca3807d15 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Fri, 17 Jan 2025 11:39:40 -0300 Subject: [PATCH 05/11] Fix tests --- .../ccip-router/src/instructions/v1/offramp.rs | 13 ++++--------- .../solana/contracts/tests/ccip/ccip_router_test.go | 11 +++++++---- chains/solana/contracts/tests/testutils/wrapped.go | 13 +++++++++++++ chains/solana/utils/ccip/ccip_messages.go | 7 ++++--- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs index 4b462a8e4..64aa07bbe 100644 --- a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs +++ b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs @@ -565,31 +565,26 @@ fn parse_messaging_accounts<'info>( source_bitmap: &u64, remaining_accounts: &'info [AccountInfo<'info>], ) -> Result<(&'info AccountInfo<'info>, &'info [AccountInfo<'info>])> { - let end_ind = if token_indexes.is_empty() { + let end_index = if token_indexes.is_empty() { remaining_accounts.len() } else { token_indexes[0] as usize }; require!( - end_ind <= remaining_accounts.len(), + 1 <= end_index && end_index <= remaining_accounts.len(), // program id and message accounts need to fit in remaining accounts CcipRouterError::InvalidInputs ); // there could be other remaining accounts used for tokens - require!( - end_ind - 1 == extra_args_accounts.len(), // assert same number of accounts passed from message and transaction - CcipRouterError::InvalidInputs - ); - let msg_program = &remaining_accounts[0]; - let msg_accounts = &remaining_accounts[1..end_ind]; + let msg_accounts = &remaining_accounts[1..end_index]; require!( logic_receiver == msg_program.key(), CcipRouterError::InvalidInputs, ); require!( - msg_accounts.len() == extra_args_accounts.len(), + msg_accounts.len() == extra_args_accounts.len(), // assert same number of accounts passed from message and transaction CcipRouterError::InvalidInputs ); diff --git a/chains/solana/contracts/tests/ccip/ccip_router_test.go b/chains/solana/contracts/tests/ccip/ccip_router_test.go index 4560610d6..75fa95ae5 100644 --- a/chains/solana/contracts/tests/ccip/ccip_router_test.go +++ b/chains/solana/contracts/tests/ccip/ccip_router_test.go @@ -4744,6 +4744,7 @@ func TestCCIPRouter(t *testing.T) { sequenceNumber := message.Header.SequenceNumber message.ExtraArgs.IsWritableBitmap = 0 message.ExtraArgs.Accounts = []solana.PublicKey{ + stubAccountPDA, solana.SystemProgramID, } @@ -4803,7 +4804,7 @@ func TestCCIPRouter(t *testing.T) { raw.AccountMetaSlice = append( raw.AccountMetaSlice, solana.NewAccountMeta(config.CcipInvalidReceiverProgram, false, false), - solana.NewAccountMeta(stubAccountPDA, true, false), + solana.NewAccountMeta(stubAccountPDA, false, false), solana.NewAccountMeta(solana.SystemProgramID, false, false), ) @@ -4900,6 +4901,7 @@ func TestCCIPRouter(t *testing.T) { sourceChainSelector := config.EvmChainSelector message, _ := testutils.CreateNextMessage(ctx, solanaGoClient, t) + message.TokenReceiver = config.ReceiverExternalExecutionConfigPDA message.TokenAmounts = []ccip_router.Any2SolanaTokenTransfer{{ SourcePoolAddress: []byte{1, 2, 3}, DestTokenAddress: token0.Mint.PublicKey(), @@ -5269,10 +5271,10 @@ func TestCCIPRouter(t *testing.T) { message, _ := testutils.CreateNextMessage(ctx, solanaGoClient, t) // To make the message go through the validations we need to specify all additional accounts used when executing the CPI - message.ExtraArgs.IsWritableBitmap = 2 + 32 + 64 + 128 + message.ExtraArgs.IsWritableBitmap = testutils.GenerateBitMapForIndexes([]int{0, 1, 5, 6, 7}) message.ExtraArgs.Accounts = []solana.PublicKey{ - config.CcipLogicReceiver, - config.ReceiverTargetAccountPDA, // writable (index = 1) + config.ReceiverExternalExecutionConfigPDA, // writable (index = 0) + config.ReceiverTargetAccountPDA, // writable (index = 1) solana.SystemProgramID, config.CcipRouterProgram, config.RouterConfigPDA, @@ -5375,6 +5377,7 @@ func TestCCIPRouter(t *testing.T) { Amount: tokens.ToLittleEndianU256(1), }} message.TokenReceiver = receiver.PublicKey() + message.LogicReceiver = solana.PublicKey{} // no logic receiver rootBytes, err := ccip.HashEvmToSolanaMessage(message, config.OnRampAddress) require.NoError(t, err) diff --git a/chains/solana/contracts/tests/testutils/wrapped.go b/chains/solana/contracts/tests/testutils/wrapped.go index 3b7f8bcd4..47a225eff 100644 --- a/chains/solana/contracts/tests/testutils/wrapped.go +++ b/chains/solana/contracts/tests/testutils/wrapped.go @@ -99,3 +99,16 @@ func MakeEvmToSolanaMessage(t *testing.T, tokenReceiver solana.PublicKey, logicR require.NoError(t, err) return msg, hash } + +// GenerateBitMapForIndexes generates a bitmap for the given indexes. + +func GenerateBitMapForIndexes(indexes []int) uint64 { + + var bitmap uint64 + + for _, index := range indexes { + bitmap |= 1 << index + } + + return bitmap +} diff --git a/chains/solana/utils/ccip/ccip_messages.go b/chains/solana/utils/ccip/ccip_messages.go index 14acf7030..a2b9a7034 100644 --- a/chains/solana/utils/ccip/ccip_messages.go +++ b/chains/solana/utils/ccip/ccip_messages.go @@ -99,13 +99,14 @@ func CreateDefaultMessageWith(sourceChainSelector uint64, sequenceNumber uint64) }, Sender: []byte{1, 2, 3}, Data: []byte{4, 5, 6}, - TokenReceiver: config.ReceiverExternalExecutionConfigPDA, LogicReceiver: config.CcipLogicReceiver, ExtraArgs: ccip_router.SolanaExtraArgs{ ComputeUnits: 1000, - IsWritableBitmap: 2, // bitmap[1] == 1 + IsWritableBitmap: 3, // [true, true, false] Accounts: []solana.PublicKey{ - config.ReceiverTargetAccountPDA, solana.SystemProgramID, + config.ReceiverExternalExecutionConfigPDA, + config.ReceiverTargetAccountPDA, + solana.SystemProgramID, }, }, OnRampAddress: config.OnRampAddress, From 11f1fc229558e9f7c3310ce6008479ac6a22eb75 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Fri, 17 Jan 2025 13:53:36 -0300 Subject: [PATCH 06/11] Fix tests --- .../ccip-router/src/instructions/v1/offramp.rs | 2 +- .../contracts/tests/ccip/ccip_router_test.go | 16 ++++++++-------- .../solana/contracts/tests/testutils/wrapped.go | 1 - chains/solana/gobindings/ccip_router/types.go | 6 ------ chains/solana/utils/ccip/ccip_messages.go | 2 +- chains/solana/utils/ccip/ccip_messages_test.go | 9 +-------- 6 files changed, 11 insertions(+), 25 deletions(-) diff --git a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs index fb1a31c99..5751d89a7 100644 --- a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs +++ b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs @@ -880,7 +880,7 @@ mod tests { let hash_result = hash(&message); assert_eq!( - "60f412fe7c28ae6981b694f92677276f767a98e0314b9a31a3c38366223e7e52", + "266b8d99e64a52fdd325f67674f56d0005dbee5e9999ff22017d5b117fbedfa3", hex::encode(hash_result) ); } diff --git a/chains/solana/contracts/tests/ccip/ccip_router_test.go b/chains/solana/contracts/tests/ccip/ccip_router_test.go index 2142fd1cb..b99ac3040 100644 --- a/chains/solana/contracts/tests/ccip/ccip_router_test.go +++ b/chains/solana/contracts/tests/ccip/ccip_router_test.go @@ -3452,7 +3452,7 @@ func TestCCIPRouter(t *testing.T) { for i, testcase := range priceUpdatesCases { t.Run(testcase.Name, func(t *testing.T) { - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3, uint8(i)}) + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SVMChainSelector, []byte{1, 2, 3, uint8(i)}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3556,7 +3556,7 @@ func TestCCIPRouter(t *testing.T) { sourceChainSelector := uint64(34) sourceChainStatePDA, err := ccip.GetSourceChainStatePDA(sourceChainSelector) require.NoError(t, err) - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, sourceChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, sourceChainSelector, config.SVMChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(sourceChainSelector, root) require.NoError(t, err) @@ -3593,7 +3593,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with an invalid interval it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SVMChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3630,7 +3630,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with an interval size bigger than supported it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SVMChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3704,7 +3704,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with a repeated merkle root, it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3, 1}) // repeated root + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SVMChainSelector, []byte{1, 2, 3, 1}) // repeated root rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3742,7 +3742,7 @@ func TestCCIPRouter(t *testing.T) { t.Run("When committing a report with an invalid min interval, it fails", func(t *testing.T) { t.Parallel() - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SVMChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3840,7 +3840,7 @@ func TestCCIPRouter(t *testing.T) { // TODO right now I'm allowing sending too many remaining_accounts, but if we want to be restrictive with that we can add a test here } - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{1, 2, 3}) + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SVMChainSelector, []byte{1, 2, 3}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) @@ -3907,7 +3907,7 @@ func TestCCIPRouter(t *testing.T) { }) t.Run("When committing a report with the exact next interval, it succeeds", func(t *testing.T) { - _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SolanaChainSelector, []byte{4, 5, 6}) + _, root := testutils.MakeAnyToSVMMessage(t, config.CcipTokenReceiver, config.CcipLogicReceiver, config.EvmChainSelector, config.SVMChainSelector, []byte{4, 5, 6}) rootPDA, err := ccip.GetCommitReportPDA(config.EvmChainSelector, root) require.NoError(t, err) diff --git a/chains/solana/contracts/tests/testutils/wrapped.go b/chains/solana/contracts/tests/testutils/wrapped.go index 7a609d842..8ed8a91fa 100644 --- a/chains/solana/contracts/tests/testutils/wrapped.go +++ b/chains/solana/contracts/tests/testutils/wrapped.go @@ -103,7 +103,6 @@ func MakeAnyToSVMMessage(t *testing.T, tokenReceiver solana.PublicKey, logicRece // GenerateBitMapForIndexes generates a bitmap for the given indexes. func GenerateBitMapForIndexes(indexes []int) uint64 { - var bitmap uint64 for _, index := range indexes { diff --git a/chains/solana/gobindings/ccip_router/types.go b/chains/solana/gobindings/ccip_router/types.go index b98903393..d49ea0898 100644 --- a/chains/solana/gobindings/ccip_router/types.go +++ b/chains/solana/gobindings/ccip_router/types.go @@ -665,16 +665,10 @@ type Any2SVMRampMessage struct { Header RampMessageHeader Sender []byte Data []byte -<<<<<<< HEAD LogicReceiver ag_solanago.PublicKey TokenReceiver ag_solanago.PublicKey - TokenAmounts []Any2SolanaTokenTransfer - ExtraArgs SolanaExtraArgs -======= - Receiver ag_solanago.PublicKey TokenAmounts []Any2SVMTokenTransfer ExtraArgs SVMExtraArgs ->>>>>>> main OnRampAddress []byte } diff --git a/chains/solana/utils/ccip/ccip_messages.go b/chains/solana/utils/ccip/ccip_messages.go index 4c72800bc..0d982d207 100644 --- a/chains/solana/utils/ccip/ccip_messages.go +++ b/chains/solana/utils/ccip/ccip_messages.go @@ -99,7 +99,7 @@ func CreateDefaultMessageWith(sourceChainSelector uint64, sequenceNumber uint64) }, Sender: []byte{1, 2, 3}, Data: []byte{4, 5, 6}, - LogicReceiver: config.ReceiverExternalExecutionConfigPDA, + LogicReceiver: config.CcipLogicReceiver, ExtraArgs: ccip_router.SVMExtraArgs{ ComputeUnits: 1000, IsWritableBitmap: 3, // [true, true, false] diff --git a/chains/solana/utils/ccip/ccip_messages_test.go b/chains/solana/utils/ccip/ccip_messages_test.go index 4bfd71814..8e13bd49e 100644 --- a/chains/solana/utils/ccip/ccip_messages_test.go +++ b/chains/solana/utils/ccip/ccip_messages_test.go @@ -24,18 +24,11 @@ func TestMessageHashing(t *testing.T) { t.Run("AnyToSVM", func(t *testing.T) { t.Parallel() -<<<<<<< HEAD - h, err := HashEvmToSolanaMessage(ccip_router.Any2SolanaRampMessage{ + h, err := HashAnyToSVMMessage(ccip_router.Any2SVMRampMessage{ Sender: sender, TokenReceiver: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), LogicReceiver: solana.MustPublicKeyFromBase58("C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8"), Data: []byte{4, 5, 6}, -======= - h, err := HashAnyToSVMMessage(ccip_router.Any2SVMRampMessage{ - Sender: sender, - Receiver: solana.MustPublicKeyFromBase58("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb"), - Data: []byte{4, 5, 6}, ->>>>>>> main Header: ccip_router.RampMessageHeader{ MessageId: [32]uint8{8, 5, 3}, SourceChainSelector: 67, From 754a41e43b9ef792f2ed60a787591fdf6c0f6ea0 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Fri, 17 Jan 2025 14:07:59 -0300 Subject: [PATCH 07/11] Use method to calculate bitmap --- .../contracts/tests/ccip/ccip_router_test.go | 2 +- .../contracts/tests/testutils/wrapped.go | 12 ------------ chains/solana/utils/ccip/ccip_messages.go | 18 +++++++++++++++--- chains/solana/utils/ccip/ccip_messages_test.go | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/chains/solana/contracts/tests/ccip/ccip_router_test.go b/chains/solana/contracts/tests/ccip/ccip_router_test.go index b99ac3040..ce03a62d4 100644 --- a/chains/solana/contracts/tests/ccip/ccip_router_test.go +++ b/chains/solana/contracts/tests/ccip/ccip_router_test.go @@ -5300,7 +5300,7 @@ func TestCCIPRouter(t *testing.T) { message, _ := testutils.CreateNextMessage(ctx, solanaGoClient, t) // To make the message go through the validations we need to specify all additional accounts used when executing the CPI - message.ExtraArgs.IsWritableBitmap = testutils.GenerateBitMapForIndexes([]int{0, 1, 5, 6, 7}) + message.ExtraArgs.IsWritableBitmap = ccip.GenerateBitMapForIndexes([]int{0, 1, 5, 6, 7}) message.ExtraArgs.Accounts = []solana.PublicKey{ config.ReceiverExternalExecutionConfigPDA, // writable (index = 0) config.ReceiverTargetAccountPDA, // writable (index = 1) diff --git a/chains/solana/contracts/tests/testutils/wrapped.go b/chains/solana/contracts/tests/testutils/wrapped.go index 8ed8a91fa..53d234ce5 100644 --- a/chains/solana/contracts/tests/testutils/wrapped.go +++ b/chains/solana/contracts/tests/testutils/wrapped.go @@ -99,15 +99,3 @@ func MakeAnyToSVMMessage(t *testing.T, tokenReceiver solana.PublicKey, logicRece require.NoError(t, err) return msg, hash } - -// GenerateBitMapForIndexes generates a bitmap for the given indexes. - -func GenerateBitMapForIndexes(indexes []int) uint64 { - var bitmap uint64 - - for _, index := range indexes { - bitmap |= 1 << index - } - - return bitmap -} diff --git a/chains/solana/utils/ccip/ccip_messages.go b/chains/solana/utils/ccip/ccip_messages.go index 0d982d207..6b4c30d22 100644 --- a/chains/solana/utils/ccip/ccip_messages.go +++ b/chains/solana/utils/ccip/ccip_messages.go @@ -102,10 +102,10 @@ func CreateDefaultMessageWith(sourceChainSelector uint64, sequenceNumber uint64) LogicReceiver: config.CcipLogicReceiver, ExtraArgs: ccip_router.SVMExtraArgs{ ComputeUnits: 1000, - IsWritableBitmap: 3, // [true, true, false] + IsWritableBitmap: GenerateBitMapForIndexes([]int{0, 1}), Accounts: []solana.PublicKey{ - config.ReceiverExternalExecutionConfigPDA, - config.ReceiverTargetAccountPDA, + config.ReceiverExternalExecutionConfigPDA, // writable (index 0) + config.ReceiverTargetAccountPDA, // writable (index 1) solana.SystemProgramID, }, }, @@ -281,3 +281,15 @@ func HashSVMToAnyMessage(msg ccip_router.SVM2AnyRampMessage) ([]byte, error) { return hash.Sum(nil), nil } + +// GenerateBitMapForIndexes generates a bitmap for the given indexes. + +func GenerateBitMapForIndexes(indexes []int) uint64 { + var bitmap uint64 + + for _, index := range indexes { + bitmap |= 1 << index + } + + return bitmap +} diff --git a/chains/solana/utils/ccip/ccip_messages_test.go b/chains/solana/utils/ccip/ccip_messages_test.go index 8e13bd49e..6c5709e4d 100644 --- a/chains/solana/utils/ccip/ccip_messages_test.go +++ b/chains/solana/utils/ccip/ccip_messages_test.go @@ -38,7 +38,7 @@ func TestMessageHashing(t *testing.T) { }, ExtraArgs: ccip_router.SVMExtraArgs{ ComputeUnits: 1000, - IsWritableBitmap: 1, + IsWritableBitmap: GenerateBitMapForIndexes([]int{0}), Accounts: []solana.PublicKey{ solana.MustPublicKeyFromBase58("CtEVnHsQzhTNWav8skikiV2oF6Xx7r7uGGa8eCDQtTjH"), }, From 2efed9af51645204c04cd7d87809ea048665b95b Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Fri, 17 Jan 2025 16:19:33 -0300 Subject: [PATCH 08/11] fix hash --- chains/solana/utils/ccip/ccip_messages_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chains/solana/utils/ccip/ccip_messages_test.go b/chains/solana/utils/ccip/ccip_messages_test.go index 6c5709e4d..3104e976c 100644 --- a/chains/solana/utils/ccip/ccip_messages_test.go +++ b/chains/solana/utils/ccip/ccip_messages_test.go @@ -55,7 +55,7 @@ func TestMessageHashing(t *testing.T) { }, config.OnRampAddress) require.NoError(t, err) - require.Equal(t, "60f412fe7c28ae6981b694f92677276f767a98e0314b9a31a3c38366223e7e52", hex.EncodeToString(h)) + require.Equal(t, "266b8d99e64a52fdd325f67674f56d0005dbee5e9999ff22017d5b117fbedfa3", hex.EncodeToString(h)) }) t.Run("SVMToAny", func(t *testing.T) { From 8ecb128b3d6ec4b7bc7ea9fd1df1854ad353dec8 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Fri, 17 Jan 2025 16:28:53 -0300 Subject: [PATCH 09/11] Fix tx size test --- chains/solana/contracts/tests/txsizing_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chains/solana/contracts/tests/txsizing_test.go b/chains/solana/contracts/tests/txsizing_test.go index 0d46deca4..adfa32834 100644 --- a/chains/solana/contracts/tests/txsizing_test.go +++ b/chains/solana/contracts/tests/txsizing_test.go @@ -73,7 +73,7 @@ func TestTransactionSizing(t *testing.T) { bz, err := tx.MarshalBinary() require.NoError(t, err) l := len(bz) - require.LessOrEqual(t, l, 1238) + require.LessOrEqual(t, l, 1242) return fmt.Sprintf("%-55s: %-4d - remaining: %d", name, l, 1232-l) } @@ -88,7 +88,7 @@ func TestTransactionSizing(t *testing.T) { sendSingleMinimalToken := ccip_router.SVM2AnyMessage{ Receiver: make([]byte, 20), Data: []byte{}, - TokenAmounts: []ccip_router.SVMTokenAmount{ccip_router.SVMTokenAmount{ + TokenAmounts: []ccip_router.SVMTokenAmount{{ Token: [32]byte{}, Amount: 0, }}, // one token From 24913cfbf9d2e6a8b55048d09ea6e8bc66f49086 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Mon, 20 Jan 2025 10:49:01 -0300 Subject: [PATCH 10/11] Fix tx sizing test --- chains/solana/contracts/tests/txsizing_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chains/solana/contracts/tests/txsizing_test.go b/chains/solana/contracts/tests/txsizing_test.go index adfa32834..24fecff3b 100644 --- a/chains/solana/contracts/tests/txsizing_test.go +++ b/chains/solana/contracts/tests/txsizing_test.go @@ -73,7 +73,7 @@ func TestTransactionSizing(t *testing.T) { bz, err := tx.MarshalBinary() require.NoError(t, err) l := len(bz) - require.LessOrEqual(t, l, 1242) + require.LessOrEqual(t, l, 1250) return fmt.Sprintf("%-55s: %-4d - remaining: %d", name, l, 1232-l) } From ebe4f3cb2df28de61229695d6b7636f459e52d2b Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Tue, 21 Jan 2025 13:30:17 -0300 Subject: [PATCH 11/11] Refactor token accounts method --- .../src/instructions/v1/offramp.rs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs index c3899a39b..423c6137a 100644 --- a/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs +++ b/chains/solana/contracts/programs/ccip-router/src/instructions/v1/offramp.rs @@ -9,7 +9,7 @@ use super::ocr3base::{ocr3_transmit, ReportContext}; use super::ocr3impl::{Ocr3ReportForCommit, Ocr3ReportForExecutionReportSingleChain}; use super::pools::{ calculate_token_pool_account_indices, get_balance, interact_with_pool, - validate_and_parse_token_accounts, CCIP_POOL_V1_RET_BYTES, + validate_and_parse_token_accounts, TokenAccounts, CCIP_POOL_V1_RET_BYTES, }; use crate::{ @@ -403,14 +403,13 @@ fn internal_execute<'info>( // note: indexes are used instead of counts in case more accounts need to be passed in remaining_accounts before token accounts // token_indexes = [2, 4] where remaining_accounts is [custom_account, custom_account, token1_account1, token1_account2, token2_account1, token2_account2] for example for (i, token_amount) in execution_report.message.token_amounts.iter().enumerate() { - let (start, end) = - calculate_token_pool_account_indices(i, token_indexes, ctx.remaining_accounts.len())?; - let acc_list = &ctx.remaining_accounts[start..end]; - let accs = validate_and_parse_token_accounts( + let accs = get_token_accounts_for( + ctx.program_id.key(), + ctx.remaining_accounts, execution_report.message.token_receiver, execution_report.message.header.source_chain_selector, - ctx.program_id.key(), - acc_list, + token_indexes, + i, )?; let router_token_pool_signer = &ctx.accounts.token_pools_signer; @@ -540,6 +539,26 @@ fn internal_execute<'info>( Ok(()) } +fn get_token_accounts_for<'a>( + router: Pubkey, + accounts: &'a [AccountInfo<'a>], + token_receiver: Pubkey, + chain_selector: u64, + token_indexes: &[u8], + i: usize, +) -> Result> { + let (start, end) = calculate_token_pool_account_indices(i, token_indexes, accounts.len())?; + + let accs = validate_and_parse_token_accounts( + token_receiver, + chain_selector, + router, + &accounts[start..end], + )?; + + Ok(accs) +} + // should_execute_messaging checks if: // 1. There is at least one account used for messaging (the first subset of accounts). This is because the first account is the program id to do the CPI // 2. AND the logic_receiver has a value different than zeros