diff --git a/.gitmodules b/.gitmodules index b04c919b6..764888dbe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,5 +12,5 @@ branch = 2b7db51f99b49eda99b44f4a044e751cb0b2e8ea [submodule "solana/lib/wormhole"] path = solana/lib/wormhole - url = https://github.com/wormholelabs-xyz/wormhole.git - branch = f69b3ae366211276fe15554f83a2d76abee0535c + url = https://github.com/wormhole-foundation/wormhole.git + branch = 33dd6a56541c2d15d3e20faa1330ba542a5fa727 diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 839efc20e..e27de4ac1 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -6971,6 +6971,7 @@ dependencies = [ [[package]] name = "wormhole-svm-definitions" version = "0.1.0" +source = "git+https://github.com/wormhole-foundation/wormhole.git?rev=33dd6a56541c2d15d3e20faa1330ba542a5fa727#33dd6a56541c2d15d3e20faa1330ba542a5fa727" dependencies = [ "borsh 1.5.0", "cfg-if", @@ -6981,6 +6982,7 @@ dependencies = [ [[package]] name = "wormhole-svm-shim" version = "0.1.0" +source = "git+https://github.com/wormhole-foundation/wormhole.git?rev=33dd6a56541c2d15d3e20faa1330ba542a5fa727#33dd6a56541c2d15d3e20faa1330ba542a5fa727" dependencies = [ "solana-program", "wormhole-svm-definitions", @@ -7171,3 +7173,11 @@ dependencies = [ "cc", "pkg-config", ] + +[[patch.unused]] +name = "wormhole-svm-definitions" +version = "0.1.0" + +[[patch.unused]] +name = "wormhole-svm-shim" +version = "0.1.0" diff --git a/solana/Cargo.toml b/solana/Cargo.toml index 563282a94..558cb4359 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -49,8 +49,8 @@ ruint = "1.9.0" cfg-if = "1.0" hex-literal = "0.4.1" bytemuck = "1.13.0" -wormhole-svm-shim = { git = "https://github.com/wormholelabs-xyz/wormhole.git", rev = "32cb65dd9ae11547f0e57d106b6974dc8ed5f52d" } -wormhole-svm-definitions = { git = "https://github.com/wormholelabs-xyz/wormhole.git", rev = "32cb65dd9ae11547f0e57d106b6974dc8ed5f52d", features = ["borsh"] } +wormhole-svm-shim = { git = "https://github.com/wormhole-foundation/wormhole.git", rev = "33dd6a56541c2d15d3e20faa1330ba542a5fa727" } +wormhole-svm-definitions = { git = "https://github.com/wormhole-foundation/wormhole.git", rev = "33dd6a56541c2d15d3e20faa1330ba542a5fa727", features = ["borsh"] } [patch."https://github.com/wormholelabs-xyz/wormhole.git"] wormhole-svm-shim = { path = "lib/wormhole/svm/wormhole-core-shims/crates/shim" } diff --git a/solana/lib/wormhole b/solana/lib/wormhole index 32cb65dd9..33dd6a565 160000 --- a/solana/lib/wormhole +++ b/solana/lib/wormhole @@ -1 +1 @@ -Subproject commit 32cb65dd9ae11547f0e57d106b6974dc8ed5f52d +Subproject commit 33dd6a56541c2d15d3e20faa1330ba542a5fa727 diff --git a/solana/modules/matching-engine-testing/tests/shimful/fast_market_order_shim.rs b/solana/modules/matching-engine-testing/tests/shimful/fast_market_order_shim.rs index 44932106b..5177a5339 100644 --- a/solana/modules/matching-engine-testing/tests/shimful/fast_market_order_shim.rs +++ b/solana/modules/matching-engine-testing/tests/shimful/fast_market_order_shim.rs @@ -80,11 +80,18 @@ pub async fn initialize_fast_market_order_shimful( ], program_id, ); + let from_endpoint = current_state + .router_endpoints() + .unwrap() + .endpoints + .get_from_and_to_endpoint_addresses(testing_context.transfer_direction) + .0; let initialize_fast_market_order_ix = initialize_fast_market_order_shimful_instruction( &payer_signer, program_id, fast_market_order, &guardian_signature_info, + &from_endpoint, ); let transaction = testing_context .create_transaction( @@ -142,6 +149,7 @@ pub fn initialize_fast_market_order_shimful_instruction( program_id: &Pubkey, fast_market_order: FastMarketOrderState, guardian_signature_info: &GuardianSignatureInfo, + from_endpoint: &Pubkey, ) -> solana_program::instruction::Instruction { let fast_market_order_account = Pubkey::find_program_address( &[ @@ -158,6 +166,7 @@ pub fn initialize_fast_market_order_shimful_instruction( fast_market_order_account: &fast_market_order_account, guardian_set: &guardian_signature_info.guardian_set_pubkey, guardian_set_signatures: &guardian_signature_info.guardian_signatures_pubkey, + from_endpoint, verify_vaa_shim_program: &WORMHOLE_VERIFY_VAA_SHIM_PID, system_program: &solana_program::system_program::ID, }; @@ -274,7 +283,6 @@ pub fn create_fast_market_order_state_from_vaa_data( close_account_refund_recipient, vaa_sequence: vaa_data.sequence, vaa_timestamp: vaa_data.vaa_time, - vaa_nonce: vaa_data.nonce, vaa_emitter_chain: vaa_data.emitter_chain, vaa_consistency_level: vaa_data.consistency_level, vaa_emitter_address: vaa_data.emitter_address, diff --git a/solana/modules/matching-engine-testing/tests/test_scenarios/create_and_close_fast_market_order.rs b/solana/modules/matching-engine-testing/tests/test_scenarios/create_and_close_fast_market_order.rs index 0adf5f10b..c2ab5eb84 100644 --- a/solana/modules/matching-engine-testing/tests/test_scenarios/create_and_close_fast_market_order.rs +++ b/solana/modules/matching-engine-testing/tests/test_scenarios/create_and_close_fast_market_order.rs @@ -69,6 +69,9 @@ pub async fn test_initialize_fast_market_order_fallback() { let instruction_triggers = vec![ InstructionTrigger::InitializeProgram(InitializeInstructionConfig::default()), + InstructionTrigger::CreateCctpRouterEndpoints( + CreateCctpRouterEndpointsInstructionConfig::default(), + ), InstructionTrigger::InitializeFastMarketOrderShim( InitializeFastMarketOrderShimInstructionConfig::default(), ), @@ -96,6 +99,9 @@ pub async fn test_close_fast_market_order_fallback() { let testing_engine = TestingEngine::new(testing_context).await; let instruction_triggers = vec![ InstructionTrigger::InitializeProgram(InitializeInstructionConfig::default()), + InstructionTrigger::CreateCctpRouterEndpoints( + CreateCctpRouterEndpointsInstructionConfig::default(), + ), InstructionTrigger::InitializeFastMarketOrderShim( InitializeFastMarketOrderShimInstructionConfig::default(), ), @@ -126,6 +132,9 @@ pub async fn test_close_fast_market_order_fallback_with_custom_refund_recipient( let testing_engine = TestingEngine::new(testing_context).await; let instruction_triggers = vec![ InstructionTrigger::InitializeProgram(InitializeInstructionConfig::default()), + InstructionTrigger::CreateCctpRouterEndpoints( + CreateCctpRouterEndpointsInstructionConfig::default(), + ), InstructionTrigger::InitializeFastMarketOrderShim( InitializeFastMarketOrderShimInstructionConfig { close_account_refund_recipient: Some(solver_1.pubkey()), @@ -238,6 +247,9 @@ pub async fn test_fast_market_order_cannot_be_closed_twice() { let testing_engine = TestingEngine::new(testing_context).await; let instruction_triggers = vec![ InstructionTrigger::InitializeProgram(InitializeInstructionConfig::default()), + InstructionTrigger::CreateCctpRouterEndpoints( + CreateCctpRouterEndpointsInstructionConfig::default(), + ), InstructionTrigger::InitializeFastMarketOrderShim( InitializeFastMarketOrderShimInstructionConfig::default(), ), @@ -286,6 +298,9 @@ pub async fn test_fast_market_order_can_be_opened_after_being_closed_by_the_same let testing_engine = TestingEngine::new(testing_context).await; let instruction_triggers = vec![ InstructionTrigger::InitializeProgram(InitializeInstructionConfig::default()), + InstructionTrigger::CreateCctpRouterEndpoints( + CreateCctpRouterEndpointsInstructionConfig::default(), + ), InstructionTrigger::InitializeFastMarketOrderShim( InitializeFastMarketOrderShimInstructionConfig::default(), ), @@ -321,6 +336,9 @@ pub async fn test_multiple_fast_market_orders_can_be_opened_and_closed_by_differ let testing_engine = TestingEngine::new(testing_context).await; let instruction_triggers = vec![ InstructionTrigger::InitializeProgram(InitializeInstructionConfig::default()), + InstructionTrigger::CreateCctpRouterEndpoints( + CreateCctpRouterEndpointsInstructionConfig::default(), + ), InstructionTrigger::InitializeFastMarketOrderShim( InitializeFastMarketOrderShimInstructionConfig { fast_market_order_id: 0, diff --git a/solana/modules/matching-engine-testing/tests/test_scenarios/execute_order.rs b/solana/modules/matching-engine-testing/tests/test_scenarios/execute_order.rs index 672f5c40f..7c73d2a85 100644 --- a/solana/modules/matching-engine-testing/tests/test_scenarios/execute_order.rs +++ b/solana/modules/matching-engine-testing/tests/test_scenarios/execute_order.rs @@ -1066,35 +1066,22 @@ pub async fn test_execute_order_shim_emitter_chain_mismatch() { InitializeFastMarketOrderShimInstructionConfig { fast_market_order_id: 1, vaa_index: 1, + expected_error: Some(ExpectedError { + instruction_index: 2, + error_code: u32::from(MatchingEngineError::InvalidEndpoint), + error_string: "InvalidEndpoint".to_string(), + }), ..InitializeFastMarketOrderShimInstructionConfig::default() }, ), ]; - let initialize_second_fast_market_order_state = testing_engine + testing_engine .execute( &mut test_context, initialize_second_fast_market_order_instruction_triggers, Some(initialize_first_fast_market_order_state), ) .await; - let instruction_triggers = vec![InstructionTrigger::ExecuteOrderShim( - ExecuteOrderInstructionConfig { - vaa_index: 1, - expected_error: Some(ExpectedError { - instruction_index: 2, - error_code: u32::from(MatchingEngineError::VaaMismatch), - error_string: "AccountNotInitialized".to_string(), - }), - ..ExecuteOrderInstructionConfig::default() - }, - )]; - testing_engine - .execute( - &mut test_context, - instruction_triggers, - Some(initialize_second_fast_market_order_state), - ) - .await; } /// Cannot execute order shim before auction duration is over diff --git a/solana/modules/matching-engine-testing/tests/testing_engine/engine.rs b/solana/modules/matching-engine-testing/tests/testing_engine/engine.rs index d194ab75c..efb1245ea 100644 --- a/solana/modules/matching-engine-testing/tests/testing_engine/engine.rs +++ b/solana/modules/matching-engine-testing/tests/testing_engine/engine.rs @@ -886,11 +886,18 @@ impl TestingEngine { ], program_id, ); + let from_endpoint_pubkey = current_state + .router_endpoints() + .unwrap() + .endpoints + .get_from_and_to_endpoint_addresses(self.testing_context.transfer_direction) + .0; let create_fast_market_order_instruction = initialize_fast_market_order_shimful_instruction( &create_fast_market_order_payer_signer, program_id, fast_market_order, &guardian_signature_info, + &from_endpoint_pubkey, ); let place_initial_offer_instruction = place_initial_offer_shimful_instruction( diff --git a/solana/modules/matching-engine-testing/tests/utils/router.rs b/solana/modules/matching-engine-testing/tests/utils/router.rs index 8ad865f90..fc3cc22b8 100644 --- a/solana/modules/matching-engine-testing/tests/utils/router.rs +++ b/solana/modules/matching-engine-testing/tests/utils/router.rs @@ -98,7 +98,6 @@ impl Deref for TestRouterEndpoints { } impl TestRouterEndpoints { - #[allow(dead_code)] pub fn get_from_and_to_endpoint_addresses( &self, transfer_direction: TransferDirection, diff --git a/solana/programs/matching-engine/src/fallback/processor/initialize_fast_market_order.rs b/solana/programs/matching-engine/src/fallback/processor/initialize_fast_market_order.rs index ee1b7c2cb..a1b0978ed 100644 --- a/solana/programs/matching-engine/src/fallback/processor/initialize_fast_market_order.rs +++ b/solana/programs/matching-engine/src/fallback/processor/initialize_fast_market_order.rs @@ -2,9 +2,9 @@ use anchor_lang::{prelude::*, Discriminator}; use bytemuck::{Pod, Zeroable}; use solana_program::{instruction::Instruction, keccak}; -use crate::{state::FastMarketOrder, ID}; +use crate::{error::MatchingEngineError, state::FastMarketOrder, ID}; -const NUM_ACCOUNTS: usize = 6; +const NUM_ACCOUNTS: usize = 7; pub struct InitializeFastMarketOrderAccounts<'ix> { /// Lamports from this signer will be used to create the new fast market @@ -12,6 +12,9 @@ pub struct InitializeFastMarketOrderAccounts<'ix> { /// close this account. // TODO: Rename to "payer". pub signer: &'ix Pubkey, // 0 + + /// The from router endpoint account for the hash of the fast market order + pub from_endpoint: &'ix Pubkey, /// Wormhole guardian set account used to check recovered pubkeys using /// [Self::guardian_set_signatures]. // TODO: Rename to "wormhole_guardian_set" @@ -70,6 +73,8 @@ impl InitializeFastMarketOrder<'_> { let InitializeFastMarketOrderAccounts { signer: payer, fast_market_order_account: new_fast_market_order, + from_endpoint, + guardian_set: wormhole_guardian_set, guardian_set_signatures: shim_guardian_signatures, verify_vaa_shim_program, @@ -77,12 +82,13 @@ impl InitializeFastMarketOrder<'_> { } = self.accounts; let accounts = vec![ - AccountMeta::new(*payer, true), - AccountMeta::new_readonly(*verify_vaa_shim_program, false), - AccountMeta::new_readonly(*wormhole_guardian_set, false), - AccountMeta::new_readonly(*shim_guardian_signatures, false), - AccountMeta::new(*new_fast_market_order, false), - AccountMeta::new_readonly(solana_program::system_program::ID, false), + AccountMeta::new(*payer, true), // 0 + AccountMeta::new_readonly(*from_endpoint, false), // 1 + AccountMeta::new_readonly(*verify_vaa_shim_program, false), // 2 + AccountMeta::new_readonly(*wormhole_guardian_set, false), // 3 + AccountMeta::new_readonly(*shim_guardian_signatures, false), // 4 + AccountMeta::new(*new_fast_market_order, false), // 5 + AccountMeta::new_readonly(solana_program::system_program::ID, false), // 6 ]; debug_assert_eq!(accounts.len(), NUM_ACCOUNTS); @@ -113,11 +119,21 @@ pub(super) fn process( // fast market order account. let payer_info = &accounts[0]; + // These accounts will be used by the Verify VAA shim program. + let from_endpoint = super::helpers::try_live_endpoint_account(&accounts[1], "from_endpoint") + .map_err(|e: Error| e.with_account_name("from_endpoint"))?; + + if fast_market_order.vaa_emitter_address != from_endpoint.address + || fast_market_order.vaa_emitter_chain != from_endpoint.chain + { + return Err(MatchingEngineError::InvalidEndpoint.into()); + } + // Verify the VAA digest with the Verify VAA shim program. super::helpers::invoke_verify_hash( - 1, // verify_vaa_shim_program_index - 2, // wormhole_guardian_set_index - 3, // shim_guardian_signatures_index + 2, // verify_vaa_shim_program_index + 3, // wormhole_guardian_set_index + 4, // shim_guardian_signatures_index data.guardian_set_bump, keccak::Hash(fast_market_order_vaa_digest), accounts, @@ -126,7 +142,7 @@ pub(super) fn process( // Create the new fast market order account and serialize the instruction // data into it. - let new_fast_market_order_info = &accounts[4]; + let new_fast_market_order_info = &accounts[1]; let (expected_fast_market_order_key, fast_market_order_bump) = Pubkey::find_program_address( &[ FastMarketOrder::SEED_PREFIX, @@ -181,6 +197,7 @@ mod test { accounts: InitializeFastMarketOrderAccounts { signer: &Default::default(), fast_market_order_account: &Default::default(), + from_endpoint: &Default::default(), verify_vaa_shim_program: &Default::default(), guardian_set: &Default::default(), guardian_set_signatures: &Default::default(), @@ -202,7 +219,6 @@ mod test { close_account_refund_recipient: Default::default(), vaa_sequence: Default::default(), vaa_timestamp: Default::default(), - vaa_nonce: Default::default(), vaa_emitter_chain: Default::default(), vaa_consistency_level: Default::default(), vaa_emitter_address: Default::default(), diff --git a/solana/programs/matching-engine/src/fallback/processor/place_initial_offer.rs b/solana/programs/matching-engine/src/fallback/processor/place_initial_offer.rs index 715fa79c2..30868f236 100644 --- a/solana/programs/matching-engine/src/fallback/processor/place_initial_offer.rs +++ b/solana/programs/matching-engine/src/fallback/processor/place_initial_offer.rs @@ -359,7 +359,6 @@ mod tests { close_account_refund_recipient: Pubkey::default(), vaa_sequence: 0, vaa_timestamp: 0, - vaa_nonce: 0, vaa_emitter_chain: 0, vaa_consistency_level: 0, vaa_emitter_address: [0_u8; 32], diff --git a/solana/programs/matching-engine/src/state/fast_market_order.rs b/solana/programs/matching-engine/src/state/fast_market_order.rs index 071fb4ffd..503e45deb 100644 --- a/solana/programs/matching-engine/src/state/fast_market_order.rs +++ b/solana/programs/matching-engine/src/state/fast_market_order.rs @@ -43,16 +43,13 @@ pub struct FastMarketOrder { pub vaa_sequence: u64, /// The timestamp of the fast transfer VAA. pub vaa_timestamp: u32, - /// The VAA nonce, which is not used and can be set to 0. - // TODO: Can be taken out. - pub vaa_nonce: u32, /// The source chain of the fast transfer VAA. (represented as a Wormhole /// chain ID). pub vaa_emitter_chain: u16, /// The consistency level of the fast transfer VAA. pub vaa_consistency_level: u8, /// Not used, but required for bytemuck serialization. - _padding: [u8; 5], + _padding: [u8; 1], } pub struct FastMarketOrderParams { @@ -70,7 +67,6 @@ pub struct FastMarketOrderParams { pub close_account_refund_recipient: Pubkey, pub vaa_sequence: u64, pub vaa_timestamp: u32, - pub vaa_nonce: u32, pub vaa_emitter_chain: u16, pub vaa_consistency_level: u8, pub vaa_emitter_address: [u8; 32], @@ -95,11 +91,10 @@ impl FastMarketOrder { close_account_refund_recipient: params.close_account_refund_recipient, vaa_sequence: params.vaa_sequence, vaa_timestamp: params.vaa_timestamp, - vaa_nonce: params.vaa_nonce, vaa_emitter_chain: params.vaa_emitter_chain, vaa_consistency_level: params.vaa_consistency_level, vaa_emitter_address: params.vaa_emitter_address, - _padding: [0_u8; 5], + _padding: [0_u8; 1], } } @@ -132,7 +127,8 @@ impl FastMarketOrder { wormhole_svm_definitions::compute_keccak_digest( keccak::hashv(&[ &self.vaa_timestamp.to_be_bytes(), - &self.vaa_nonce.to_be_bytes(), + // The nonce is 0 + &0_u32.to_be_bytes(), &self.vaa_emitter_chain.to_be_bytes(), &self.vaa_emitter_address, &self.vaa_sequence.to_be_bytes(),