diff --git a/crates/sui-bridge/src/e2e_tests/basic.rs b/crates/sui-bridge/src/e2e_tests/basic.rs index 072d8e6a99304..d71790aa3a7de 100644 --- a/crates/sui-bridge/src/e2e_tests/basic.rs +++ b/crates/sui-bridge/src/e2e_tests/basic.rs @@ -3,7 +3,6 @@ use crate::abi::{eth_sui_bridge, EthBridgeEvent, EthSuiBridge}; use crate::client::bridge_authority_aggregator::BridgeAuthorityAggregator; -use crate::e2e_tests::test_utils::BridgeTestCluster; use crate::e2e_tests::test_utils::{get_signatures, BridgeTestClusterBuilder}; use crate::events::{ SuiBridgeEvent, SuiToEthTokenBridgeV1, TokenTransferApproved, TokenTransferClaimed, @@ -21,7 +20,6 @@ use std::collections::{HashMap, HashSet}; use std::path::Path; -use anyhow::anyhow; use std::sync::Arc; use sui_json_rpc_types::{ SuiExecutionStatus, SuiTransactionBlockEffectsAPI, SuiTransactionBlockResponse, @@ -33,7 +31,6 @@ use sui_types::bridge::{BridgeChainId, BridgeTokenMetadata, BRIDGE_MODULE_NAME, use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder; use sui_types::transaction::{ObjectArg, TransactionData}; use sui_types::{TypeTag, BRIDGE_PACKAGE_ID}; -use tap::TapFallible; use tracing::info; #[tokio::test(flavor = "multi_thread", worker_threads = 8)] @@ -49,18 +46,31 @@ async fn test_bridge_from_eth_to_sui_to_eth() { .build() .await; - let (eth_signer, _) = bridge_test_cluster + let (eth_signer, eth_address) = bridge_test_cluster .get_eth_signer_and_address() .await .unwrap(); + let sui_client = bridge_test_cluster.sui_client(); + let sui_bridge_client = bridge_test_cluster.sui_bridge_client().await.unwrap(); let sui_address = bridge_test_cluster.sui_user_address(); let amount = 42; let sui_amount = amount * 100_000_000; - initiate_bridge_eth_to_sui(&bridge_test_cluster, amount, sui_amount, TOKEN_ID_ETH, 0) - .await - .unwrap(); + initiate_bridge_eth_to_sui( + &sui_bridge_client, + ð_signer, + bridge_test_cluster.contracts().sui_bridge, + sui_address, + eth_address, + eth_chain_id, + sui_chain_id, + amount, + sui_amount, + TOKEN_ID_ETH, + 0, + ) + .await; let events = bridge_test_cluster .new_bridge_events( HashSet::from_iter([ @@ -73,8 +83,7 @@ async fn test_bridge_from_eth_to_sui_to_eth() { // There are exactly 1 approved and 1 claimed event assert_eq!(events.len(), 2); - let eth_coin = bridge_test_cluster - .sui_client() + let eth_coin = sui_client .coin_read_api() .get_all_coins(sui_address, None, None) .await @@ -88,17 +97,28 @@ async fn test_bridge_from_eth_to_sui_to_eth() { // Now let the recipient send the coin back to ETH let eth_address_1 = EthAddress::random(); + let bridge_obj_arg = sui_bridge_client + .get_mutable_bridge_object_arg_must_succeed() + .await; let nonce = 0; + let sui_token_type_tags = sui_bridge_client.get_token_id_map().await.unwrap(); + let sui_to_eth_bridge_action = initiate_bridge_sui_to_eth( - &bridge_test_cluster, + &sui_bridge_client, + &sui_client, + sui_address, + bridge_test_cluster.wallet_mut(), + eth_chain_id, + sui_chain_id, eth_address_1, eth_coin.object_ref(), nonce, + bridge_obj_arg, sui_amount, + &sui_token_type_tags, ) - .await - .unwrap(); + .await; let events = bridge_test_cluster .new_bridge_events( HashSet::from_iter([ @@ -113,8 +133,7 @@ async fn test_bridge_from_eth_to_sui_to_eth() { assert_eq!(events.len(), 2); // Test `get_parsed_token_transfer_message` - let parsed_msg = bridge_test_cluster - .bridge_client() + let parsed_msg = sui_bridge_client .get_parsed_token_transfer_message(sui_chain_id, nonce) .await .unwrap() @@ -134,7 +153,7 @@ async fn test_bridge_from_eth_to_sui_to_eth() { assert_eq!(parsed_msg.parsed_payload.amount, sui_amount); let message = eth_sui_bridge::Message::from(sui_to_eth_bridge_action); - let signatures = get_signatures(bridge_test_cluster.bridge_client(), nonce, sui_chain_id).await; + let signatures = get_signatures(&sui_bridge_client, nonce, sui_chain_id).await; let eth_sui_bridge = EthSuiBridge::new( bridge_test_cluster.contracts().sui_bridge, @@ -176,6 +195,8 @@ async fn test_add_new_coins_on_sui() { ) .await; + let sui_bridge_client = bridge_test_cluster.sui_bridge_client().await.unwrap(); + info!("Starting bridge cluster"); bridge_test_cluster.set_approved_governance_actions_for_next_start(vec![ @@ -191,8 +212,7 @@ async fn test_add_new_coins_on_sui() { info!("Bridge cluster is up"); let bridge_committee = Arc::new( - bridge_test_cluster - .bridge_client() + sui_bridge_client .get_bridge_committee() .await .expect("Failed to get bridge committee"), @@ -225,11 +245,7 @@ async fn test_add_new_coins_on_sui() { info!("Approved new token"); // Assert new token is correctly added - let treasury_summary = bridge_test_cluster - .bridge_client() - .get_treasury_summary() - .await - .unwrap(); + let treasury_summary = sui_bridge_client.get_treasury_summary().await.unwrap(); assert_eq!(treasury_summary.id_token_type_map.len(), 5); // 4 + 1 new token let (id, _type) = treasury_summary .id_token_type_map @@ -256,29 +272,29 @@ pub(crate) async fn deposit_native_eth_to_sol_contract( signer: &EthSigner, contract_address: EthAddress, sui_recipient_address: SuiAddress, - sui_chain_id: BridgeChainId, + sui_chain_id: u8, amount: u64, ) -> ContractCall { let contract = EthSuiBridge::new(contract_address, signer.clone().into()); let sui_recipient_address = sui_recipient_address.to_vec().into(); let amount = U256::from(amount) * U256::exp10(18); // 1 ETH contract - .bridge_eth(sui_recipient_address, sui_chain_id as u8) + .bridge_eth(sui_recipient_address, sui_chain_id) .value(amount) } async fn deposit_eth_to_sui_package( sui_client: &SuiClient, sui_address: SuiAddress, - wallet_context: &WalletContext, - target_chain: BridgeChainId, + wallet_context: &mut WalletContext, + target_chain: u8, target_address: EthAddress, token: ObjectRef, bridge_object_arg: ObjectArg, sui_token_type_tags: &HashMap, -) -> Result { +) -> SuiTransactionBlockResponse { let mut builder = ProgrammableTransactionBuilder::new(); - let arg_target_chain = builder.pure(target_chain as u8).unwrap(); + let arg_target_chain = builder.pure(target_chain).unwrap(); let arg_target_address = builder.pure(target_address.as_bytes()).unwrap(); let arg_token = builder.obj(ObjectArg::ImmOrOwnedObject(token)).unwrap(); let arg_bridge = builder.obj(bridge_object_arg).unwrap(); @@ -309,29 +325,26 @@ async fn deposit_eth_to_sui_package( .unwrap(), ); let tx = wallet_context.sign_transaction(&tx_data); - wallet_context.execute_transaction_may_fail(tx).await + wallet_context.execute_transaction_must_succeed(tx).await } -pub async fn initiate_bridge_eth_to_sui( - bridge_test_cluster: &BridgeTestCluster, +async fn initiate_bridge_eth_to_sui( + sui_bridge_client: &SuiBridgeClient, + eth_signer: &EthSigner, + sui_bridge_contract_address: EthAddress, + sui_address: SuiAddress, + eth_address: EthAddress, + eth_chain_id: u8, + sui_chain_id: u8, amount: u64, sui_amount: u64, token_id: u8, nonce: u64, -) -> Result<(), anyhow::Error> { +) { info!("Depositing Eth to Solidity contract"); - let (eth_signer, eth_address) = bridge_test_cluster - .get_eth_signer_and_address() - .await - .unwrap(); - - let sui_address = bridge_test_cluster.sui_user_address(); - let sui_chain_id = bridge_test_cluster.sui_chain_id(); - let eth_chain_id = bridge_test_cluster.eth_chain_id(); - let eth_tx = deposit_native_eth_to_sol_contract( - ð_signer, - bridge_test_cluster.contracts().sui_bridge, + eth_signer, + sui_bridge_contract_address, sui_address, sui_chain_id, amount, @@ -351,9 +364,9 @@ pub async fn initiate_bridge_eth_to_sui( unreachable!(); }; // assert eth log matches - assert_eq!(eth_bridge_event.source_chain_id, eth_chain_id as u8); + assert_eq!(eth_bridge_event.source_chain_id, eth_chain_id); assert_eq!(eth_bridge_event.nonce, nonce); - assert_eq!(eth_bridge_event.destination_chain_id, sui_chain_id as u8); + assert_eq!(eth_bridge_event.destination_chain_id, sui_chain_id); assert_eq!(eth_bridge_event.token_id, token_id); assert_eq!(eth_bridge_event.sui_adjusted_amount, sui_amount); assert_eq!(eth_bridge_event.sender_address, eth_address); @@ -361,58 +374,40 @@ pub async fn initiate_bridge_eth_to_sui( info!("Deposited Eth to Solidity contract"); wait_for_transfer_action_status( - bridge_test_cluster.bridge_client(), + sui_bridge_client, eth_chain_id, - nonce, + 0, BridgeActionStatus::Claimed, ) - .await - .tap_ok(|_| { - info!("Eth to Sui bridge transfer claimed"); - }) + .await; + info!("Eth to Sui bridge transfer claimed"); } -pub async fn initiate_bridge_sui_to_eth( - bridge_test_cluster: &BridgeTestCluster, +async fn initiate_bridge_sui_to_eth( + sui_bridge_client: &SuiBridgeClient, + sui_client: &SuiClient, + sui_address: SuiAddress, + wallet_context: &mut WalletContext, + eth_chain_id: u8, + sui_chain_id: u8, eth_address: EthAddress, token: ObjectRef, nonce: u64, + bridge_object_arg: ObjectArg, sui_amount: u64, -) -> Result { - let bridge_object_arg = bridge_test_cluster - .bridge_client() - .get_mutable_bridge_object_arg_must_succeed() - .await; - let sui_client = bridge_test_cluster.sui_client(); - let token_types = bridge_test_cluster - .bridge_client() - .get_token_id_map() - .await - .unwrap(); - let sui_address = bridge_test_cluster.sui_user_address(); - - let resp = match deposit_eth_to_sui_package( + sui_token_type_tags: &HashMap, +) -> SuiToEthBridgeAction { + let resp = deposit_eth_to_sui_package( sui_client, sui_address, - bridge_test_cluster.wallet(), - bridge_test_cluster.eth_chain_id(), + wallet_context, + eth_chain_id, eth_address, token, bridge_object_arg, - &token_types, + sui_token_type_tags, ) - .await - { - Ok(resp) => { - if !resp.status_ok().unwrap() { - return Err(anyhow!("Sui TX error")); - } else { - resp - } - } - Err(e) => return Err(e), - }; - + .await; let sui_events = resp.events.unwrap().data; let bridge_event = sui_events .iter() @@ -431,12 +426,12 @@ pub async fn initiate_bridge_sui_to_eth( info!("Deposited Eth to move package"); assert_eq!(bridge_event.sui_bridge_event.nonce, nonce); assert_eq!( - bridge_event.sui_bridge_event.sui_chain_id, - bridge_test_cluster.sui_chain_id() + bridge_event.sui_bridge_event.sui_chain_id as u8, + sui_chain_id ); assert_eq!( - bridge_event.sui_bridge_event.eth_chain_id, - bridge_test_cluster.eth_chain_id() + bridge_event.sui_bridge_event.eth_chain_id as u8, + eth_chain_id ); assert_eq!(bridge_event.sui_bridge_event.sui_address, sui_address); assert_eq!(bridge_event.sui_bridge_event.eth_address, eth_address); @@ -448,39 +443,38 @@ pub async fn initiate_bridge_sui_to_eth( // Wait for the bridge action to be approved wait_for_transfer_action_status( - bridge_test_cluster.bridge_client(), - bridge_test_cluster.sui_chain_id(), + sui_bridge_client, + sui_chain_id, nonce, BridgeActionStatus::Approved, ) - .await - .unwrap(); + .await; info!("Sui to Eth bridge transfer approved"); - Ok(bridge_event) + bridge_event } async fn wait_for_transfer_action_status( sui_bridge_client: &SuiBridgeClient, - chain_id: BridgeChainId, + chain_id: u8, nonce: u64, status: BridgeActionStatus, -) -> Result<(), anyhow::Error> { +) { // Wait for the bridge action to be approved let now = std::time::Instant::now(); loop { let res = sui_bridge_client - .get_token_transfer_action_onchain_status_until_success(chain_id as u8, nonce) + .get_token_transfer_action_onchain_status_until_success(chain_id, nonce) .await; if res == status { - return Ok(()); + break; } if now.elapsed().as_secs() > 30 { - return Err(anyhow!( - "Timeout waiting for token transfer action to be {:?}. chain_id: {chain_id:?}, nonce: {nonce}. Time elapsed: {:?}", + panic!( + "Timeout waiting for token transfer action to be {:?}. chain_id: {chain_id}, nonce: {nonce}. Time elapsed: {:?}", status, now.elapsed(), - )); + ); } tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; } diff --git a/crates/sui-bridge/src/e2e_tests/complex.rs b/crates/sui-bridge/src/e2e_tests/complex.rs deleted file mode 100644 index 4c59c7f645631..0000000000000 --- a/crates/sui-bridge/src/e2e_tests/complex.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use crate::client::bridge_authority_aggregator::BridgeAuthorityAggregator; -use crate::e2e_tests::basic::initiate_bridge_eth_to_sui; -use crate::e2e_tests::basic::initiate_bridge_sui_to_eth; -use crate::e2e_tests::test_utils::BridgeTestClusterBuilder; -use crate::sui_transaction_builder::build_sui_transaction; -use crate::types::{BridgeAction, EmergencyAction}; -use crate::types::{BridgeActionStatus, EmergencyActionType}; -use ethers::types::Address as EthAddress; -use std::sync::Arc; -use sui_json_rpc_types::SuiExecutionStatus; -use sui_json_rpc_types::SuiTransactionBlockEffectsAPI; -use sui_types::bridge::{BridgeChainId, TOKEN_ID_ETH}; -use tracing::info; - -#[tokio::test] -async fn test_sui_bridge_paused() { - telemetry_subscribers::init_for_testing(); - - // approve pause action in bridge nodes - let pause_action = BridgeAction::EmergencyAction(EmergencyAction { - nonce: 0, - chain_id: BridgeChainId::SuiCustom, - action_type: EmergencyActionType::Pause, - }); - - let unpause_action = BridgeAction::EmergencyAction(EmergencyAction { - nonce: 1, - chain_id: BridgeChainId::SuiCustom, - action_type: EmergencyActionType::Unpause, - }); - - // Setup bridge test env - let bridge_test_cluster = BridgeTestClusterBuilder::new() - .with_eth_env(true) - .with_approved_governance_actions(vec![ - vec![pause_action.clone(), unpause_action.clone()], - vec![pause_action.clone(), unpause_action.clone()], - vec![pause_action.clone(), unpause_action.clone()], - vec![], - ]) - .with_bridge_cluster(true) - .build() - .await; - - let bridge_client = bridge_test_cluster.bridge_client(); - let sui_address = bridge_test_cluster.sui_user_address(); - let sui_token_type_tags = bridge_client.get_token_id_map().await.unwrap(); - - // verify bridge are not paused - assert!(!bridge_client.get_bridge_summary().await.unwrap().is_frozen); - - // try bridge from eth and verify it works on sui - initiate_bridge_eth_to_sui(&bridge_test_cluster, 10, 10 * 100_000_000, TOKEN_ID_ETH, 0) - .await - .unwrap(); - // verify Eth was transferred to Sui address - let eth_coin_type = sui_token_type_tags.get(&TOKEN_ID_ETH).unwrap(); - let eth_coin = bridge_client - .sui_client() - .coin_read_api() - .get_coins(sui_address, Some(eth_coin_type.to_string()), None, None) - .await - .unwrap() - .data; - assert_eq!(1, eth_coin.len()); - - // get pause bridge signatures from committee - let bridge_committee = Arc::new(bridge_client.get_bridge_committee().await.unwrap()); - let agg = BridgeAuthorityAggregator::new(bridge_committee); - let certified_action = agg - .request_committee_signatures(pause_action) - .await - .unwrap(); - - // execute pause bridge on sui - let gas = bridge_test_cluster - .wallet() - .get_one_gas_object_owned_by_address(sui_address) - .await - .unwrap() - .unwrap(); - - let tx = build_sui_transaction( - sui_address, - &gas, - certified_action, - bridge_client - .get_mutable_bridge_object_arg_must_succeed() - .await, - &sui_token_type_tags, - 1000, - ) - .unwrap(); - - let response = bridge_test_cluster.sign_and_execute_transaction(&tx).await; - assert_eq!( - response.effects.unwrap().status(), - &SuiExecutionStatus::Success - ); - info!("Bridge paused"); - - // verify bridge paused - assert!(bridge_client.get_bridge_summary().await.unwrap().is_frozen); - - // Transfer from eth to sui should fail on Sui - let eth_to_sui_bridge_action = - initiate_bridge_eth_to_sui(&bridge_test_cluster, 10, 10 * 100_000_000, TOKEN_ID_ETH, 1) - .await; - assert!(eth_to_sui_bridge_action.is_err()); - // message should not be recorded on Sui when the bridge is paused - let res = bridge_test_cluster - .bridge_client() - .get_token_transfer_action_onchain_status_until_success( - bridge_test_cluster.eth_chain_id() as u8, - 1, - ) - .await; - assert_eq!(BridgeActionStatus::NotFound, res); - // Transfer from Sui to eth should fail - let sui_to_eth_bridge_action = initiate_bridge_sui_to_eth( - &bridge_test_cluster, - EthAddress::random(), - eth_coin.first().unwrap().object_ref(), - 0, - 10, - ) - .await; - assert!(sui_to_eth_bridge_action.is_err()) -} diff --git a/crates/sui-bridge/src/e2e_tests/mod.rs b/crates/sui-bridge/src/e2e_tests/mod.rs index 26ee8f143271a..0f30720708fdd 100644 --- a/crates/sui-bridge/src/e2e_tests/mod.rs +++ b/crates/sui-bridge/src/e2e_tests/mod.rs @@ -2,5 +2,4 @@ // SPDX-License-Identifier: Apache-2.0 mod basic; -mod complex; pub mod test_utils; diff --git a/crates/sui-bridge/src/e2e_tests/test_utils.rs b/crates/sui-bridge/src/e2e_tests/test_utils.rs index a69fb5d60341f..43be5d62176fa 100644 --- a/crates/sui-bridge/src/e2e_tests/test_utils.rs +++ b/crates/sui-bridge/src/e2e_tests/test_utils.rs @@ -72,21 +72,16 @@ pub const TEST_PK: &str = "0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1 /// structs that are needed for testing. pub struct BridgeTestCluster { pub test_cluster: TestCluster, - bridge_client: SuiBridgeClient, eth_environment: EthBridgeEnvironment, bridge_node_handles: Option>>, approved_governance_actions_for_next_start: Option>>, bridge_tx_cursor: Option, - eth_chain_id: BridgeChainId, - sui_chain_id: BridgeChainId, } pub struct BridgeTestClusterBuilder { with_eth_env: bool, with_bridge_cluster: bool, approved_governance_actions: Option>>, - eth_chain_id: BridgeChainId, - sui_chain_id: BridgeChainId, } impl Default for BridgeTestClusterBuilder { @@ -101,8 +96,6 @@ impl BridgeTestClusterBuilder { with_eth_env: false, with_bridge_cluster: false, approved_governance_actions: None, - eth_chain_id: BridgeChainId::EthCustom, - sui_chain_id: BridgeChainId::SuiCustom, } } @@ -124,16 +117,6 @@ impl BridgeTestClusterBuilder { self } - pub fn with_sui_chain_id(mut self, chain_id: BridgeChainId) -> Self { - self.sui_chain_id = chain_id; - self - } - - pub fn with_eth_chain_id(mut self, chain_id: BridgeChainId) -> Self { - self.eth_chain_id = chain_id; - self - } - pub async fn build(self) -> BridgeTestCluster { init_all_struct_tags(); std::env::set_var("__TEST_ONLY_CONSENSUS_USE_LONG_MIN_ROUND_DELAY", "1"); @@ -162,18 +145,13 @@ impl BridgeTestClusterBuilder { .await, ); } - let bridge_client = SuiBridgeClient::new(&test_cluster.fullnode_handle.rpc_url) - .await - .unwrap(); + BridgeTestCluster { test_cluster, - bridge_client, eth_environment, bridge_node_handles, approved_governance_actions_for_next_start: self.approved_governance_actions, bridge_tx_cursor: None, - sui_chain_id: self.sui_chain_id, - eth_chain_id: self.eth_chain_id, } } @@ -221,26 +199,18 @@ impl BridgeTestCluster { Ok((eth_signer, eth_address)) } - pub fn bridge_client(&self) -> &SuiBridgeClient { - &self.bridge_client + pub async fn sui_bridge_client(&self) -> anyhow::Result { + SuiBridgeClient::new(&self.test_cluster.fullnode_handle.rpc_url).await } - pub fn sui_client(&self) -> &SuiClient { - &self.test_cluster.fullnode_handle.sui_client + pub fn sui_client(&self) -> SuiClient { + self.test_cluster.fullnode_handle.sui_client.clone() } pub fn sui_user_address(&self) -> SuiAddress { self.test_cluster.get_address_0() } - pub fn sui_chain_id(&self) -> BridgeChainId { - self.sui_chain_id - } - - pub fn eth_chain_id(&self) -> BridgeChainId { - self.eth_chain_id - } - pub fn contracts(&self) -> &DeployedSolContracts { self.eth_environment.contracts() } @@ -253,7 +223,7 @@ impl BridgeTestCluster { self.test_cluster.wallet_mut() } - pub fn wallet(&self) -> &WalletContext { + pub fn wallet(&mut self) -> &WalletContext { &self.test_cluster.wallet }