diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/snowbridge.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/snowbridge.rs index 6c04504f6b..48cc61a0e9 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/snowbridge.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/snowbridge.rs @@ -30,6 +30,9 @@ use kusama_system_emulated_network::{ penpal_emulated_chain::CustomizableAssetFromSystemAssetHub, BridgeHubKusamaParaSender as BridgeHubKusamaSender, }; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; use snowbridge_core::{ gwei, inbound::{InboundQueueFixture, Log, Message, Proof}, @@ -41,7 +44,7 @@ use snowbridge_pallet_system::PricingParametersOf; use snowbridge_router_primitives::inbound::{ Command, Destination, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, }; -use sp_core::{H160, H256}; +use sp_core::{H160, H256, U256}; use sp_runtime::{DispatchError::Token, FixedU128, TokenError::FundsUnavailable}; use system_parachains_constants::kusama::currency::UNITS; @@ -50,6 +53,9 @@ const CHAIN_ID: u64 = 1; const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); const GATEWAY_ADDRESS: [u8; 20] = hex!("EDa338E4dC46038493b885327842fD3E301CaB39"); +const INSUFFICIENT_XCM_FEE: u128 = 1000; +const XCM_FEE: u128 = 4_000_000_000; +const WETH_AMOUNT: u128 = 1_000_000_000; #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum ControlCall { @@ -82,11 +88,13 @@ pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult { /// Create an agent on Ethereum. An agent is a representation of an entity in the Polkadot /// ecosystem (like a parachain) on Ethereum. #[test] -#[ignore] fn create_agent() { let origin_para: u32 = 1001; // Fund the origin parachain sovereign account so that it can pay execution fees. BridgeHubKusama::fund_para_sovereign(origin_para.into(), INITIAL_FUND); + // Fund Treasury account with ED so that when create agent fees are paid to treasury, + // the treasury account may exist. + BridgeHubKusama::fund_accounts(vec![(RelayTreasuryPalletAccount::get(), INITIAL_FUND)]); let sudo_origin = ::RuntimeOrigin::root(); let destination = Kusama::child_location_of(BridgeHubKusama::para_id()).into(); @@ -139,11 +147,13 @@ fn create_agent() { /// Create a channel for a consensus system. A channel is a bidirectional messaging channel /// between BridgeHub and Ethereum. #[test] -#[ignore] fn create_channel() { let origin_para: u32 = 1001; // Fund AssetHub sovereign account so that it can pay execution fees. BridgeHubKusama::fund_para_sovereign(origin_para.into(), INITIAL_FUND); + // Fund Treasury account with ED so that when create agent fees are paid to treasury, + // the treasury account may exist. + BridgeHubKusama::fund_accounts(vec![(RelayTreasuryPalletAccount::get(), INITIAL_FUND)]); let sudo_origin = ::RuntimeOrigin::root(); let destination: VersionedLocation = @@ -230,8 +240,15 @@ fn register_weth_token_from_ethereum_to_asset_hub() { vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], )); // Construct RegisterToken message and sent to inbound queue - let register_token_message = make_register_token_message(); - assert_ok!(send_inbound_message(register_token_message.clone())); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubKusama::para_id()).unwrap(); assert_expected_events!( BridgeHubKusama, @@ -271,6 +288,7 @@ fn send_token_from_ethereum_to_penpal() { // Fund ethereum sovereign on AssetHub AssetHubKusama::fund_accounts(vec![(ethereum_sovereign_account(), INITIAL_FUND)]); + // Create asset on the Penpal parachain. PenpalA::execute_with(|| { // Set the trusted asset location from AH, in this case, Ethereum. assert_ok!(::System::set_storage( @@ -281,7 +299,6 @@ fn send_token_from_ethereum_to_penpal() { )], )); - // Create asset on the Penpal parachain. assert_ok!(::ForeignAssets::create( ::RuntimeOrigin::signed(PenpalASender::get()), weth_asset_location.clone(), @@ -386,10 +403,37 @@ fn send_token_from_ethereum_to_asset_hub() { )); // Construct RegisterToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_register_token_message())); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubKusama::para_id()).unwrap(); + + assert_expected_events!( + BridgeHubKusama, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); // Construct SendToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_send_token_message())); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: AssetHubKusamaReceiver::get().into() }, + amount: WETH_AMOUNT, + fee: XCM_FEE, + }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubKusama::para_id()).unwrap(); // Check that the message was sent assert_expected_events!( @@ -436,11 +480,10 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { (RelayTreasuryPalletAccount::get(), INITIAL_FUND), ]); AssetHubKusama::fund_accounts(vec![ - (AssetHubPolkadotReceiver::get(), INITIAL_FUND), + (AssetHubKusamaReceiver::get(), INITIAL_FUND), (ethereum_sovereign_account(), INITIAL_FUND), ]); - const WETH_AMOUNT: u128 = 1_000_000_000; let base_fee = 2_750_872_500_000u128; AssetHubKusama::execute_with(|| { @@ -473,8 +516,15 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], )); - // Construct RegisterToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_register_token_message())); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubKusama::para_id()).unwrap(); // Check that the register token message was sent using xcm assert_expected_events!( @@ -485,7 +535,19 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { ); // Construct SendToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_send_token_message())); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: AssetHubKusamaReceiver::get().into() }, + amount: WETH_AMOUNT, + fee: XCM_FEE, + }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubKusama::para_id()).unwrap(); // Check that the send token message was sent using xcm assert_expected_events!( @@ -538,13 +600,16 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { AssetHubKusamaReceiver::get(), ); // Send the Weth back to Ethereum - assert_ok!(::PolkadotXcm::reserve_transfer_assets( - RuntimeOrigin::signed(AssetHubKusamaReceiver::get()), - Box::new(destination), - Box::new(beneficiary), - Box::new(multi_assets), - 0, - )); + assert_ok!( + ::PolkadotXcm::limited_reserve_transfer_assets( + RuntimeOrigin::signed(AssetHubKusamaReceiver::get()), + Box::new(destination), + Box::new(beneficiary), + Box::new(multi_assets), + 0, + Unlimited, + ) + ); let free_balance_after = ::Balances::free_balance( AssetHubKusamaReceiver::get(), @@ -603,10 +668,15 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], )); - // Construct RegisterToken message and sent to inbound queue - let message = todo!(); // FAIL-CI @clara this does not exist anymore - // make_register_token_with_infufficient_fee_message(); - assert_ok!(send_inbound_message(message)); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: INSUFFICIENT_XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubKusama::para_id()).unwrap(); assert_expected_events!( BridgeHubKusama, @@ -676,11 +746,84 @@ fn ethereum_sovereign_account() -> AccountId { } fn make_register_token_message() -> InboundQueueFixture { - // FAIL-CI @clara - todo!() -} - -fn make_send_token_message() -> InboundQueueFixture { - // FAIL-CI @clara - todo!() + InboundQueueFixture{ + message: Message { + event_log: Log{ + address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), + topics: vec![ + hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), + hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), + hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), + ], + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e0001000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), + }, + proof: Proof { + receipt_proof: (vec![ + hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(), + ], vec![ + hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e0001000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), + ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("308e4c20194c0c77155c65a2d2c7dcd0ec6a7b20bdeb002c065932149fe0aa1b").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("62d13e9a073dc7cf609005b5531bb208c8686f18f7c8ae02d76232d83ae41a21").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), + ], + } + } + }, + finalized_header: BeaconHeader { + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), + }, + block_roots_root: hex!("3adb5c78afd49ef17160ca7fc38b47228cbb13a317709c86bb6f51d799ba9ab6").into(), + } } diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs index 5aa68e8268..3c14e2cc57 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs @@ -30,7 +30,9 @@ use polkadot_system_emulated_network::{ penpal_emulated_chain::CustomizableAssetFromSystemAssetHub, BridgeHubPolkadotParaSender as BridgeHubPolkadotSender, }; -use snowbridge_beacon_primitives::BeaconHeader; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; use snowbridge_core::{ gwei, inbound::{InboundQueueFixture, Log, Message, Proof}, @@ -42,7 +44,7 @@ use snowbridge_pallet_system::PricingParametersOf; use snowbridge_router_primitives::inbound::{ Command, Destination, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, }; -use sp_core::{H160, H256}; +use sp_core::{H160, H256, U256}; use sp_runtime::{DispatchError::Token, FixedU128, TokenError::FundsUnavailable}; use system_parachains_constants::polkadot::currency::UNITS; @@ -51,6 +53,9 @@ const CHAIN_ID: u64 = 1; const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); const GATEWAY_ADDRESS: [u8; 20] = hex!("EDa338E4dC46038493b885327842fD3E301CaB39"); +const INSUFFICIENT_XCM_FEE: u128 = 1000; +const XCM_FEE: u128 = 4_000_000_000; +const WETH_AMOUNT: u128 = 1_000_000_000; #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum ControlCall { @@ -83,11 +88,13 @@ pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult { /// Create an agent on Ethereum. An agent is a representation of an entity in the Polkadot /// ecosystem (like a parachain) on Ethereum. #[test] -#[ignore] fn create_agent() { let origin_para: u32 = 1001; // Fund the origin parachain sovereign account so that it can pay execution fees. BridgeHubPolkadot::fund_para_sovereign(origin_para.into(), INITIAL_FUND); + // Fund Treasury account with ED so that when create agent fees are paid to treasury, + // the treasury account may exist. + BridgeHubPolkadot::fund_accounts(vec![(RelayTreasuryPalletAccount::get(), INITIAL_FUND)]); let sudo_origin = ::RuntimeOrigin::root(); let destination = Polkadot::child_location_of(BridgeHubPolkadot::para_id()).into(); @@ -140,11 +147,13 @@ fn create_agent() { /// Create a channel for a consensus system. A channel is a bidirectional messaging channel /// between BridgeHub and Ethereum. #[test] -#[ignore] fn create_channel() { let origin_para: u32 = 1001; // Fund AssetHub sovereign account so that it can pay execution fees. BridgeHubPolkadot::fund_para_sovereign(origin_para.into(), INITIAL_FUND); + // Fund Treasury account with ED so that when create agent fees are paid to treasury, + // the treasury account may exist. + BridgeHubPolkadot::fund_accounts(vec![(RelayTreasuryPalletAccount::get(), INITIAL_FUND)]); let sudo_origin = ::RuntimeOrigin::root(); let destination: VersionedLocation = @@ -231,8 +240,15 @@ fn register_weth_token_from_ethereum_to_asset_hub() { vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], )); // Construct RegisterToken message and sent to inbound queue - let register_token_message = make_register_token_message(); - assert_ok!(send_inbound_message(register_token_message.clone())); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); assert_expected_events!( BridgeHubPolkadot, @@ -387,10 +403,39 @@ fn send_token_from_ethereum_to_asset_hub() { )); // Construct RegisterToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_register_token_message())); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); + + assert_expected_events!( + BridgeHubPolkadot, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); // Construct SendToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_send_token_message())); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { + id: AssetHubPolkadotReceiver::get().into(), + }, + amount: WETH_AMOUNT, + fee: XCM_FEE, + }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); // Check that the message was sent assert_expected_events!( @@ -441,7 +486,6 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { (ethereum_sovereign_account(), INITIAL_FUND), ]); - const WETH_AMOUNT: u128 = 1_000_000_000; let base_fee = 2_750_872_500_000u128; AssetHubPolkadot::execute_with(|| { @@ -474,8 +518,15 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], )); - // Construct RegisterToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_register_token_message())); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); // Check that the register token message was sent using xcm assert_expected_events!( @@ -486,7 +537,21 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { ); // Construct SendToken message and sent to inbound queue - assert_ok!(send_inbound_message(make_send_token_message())); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { + id: AssetHubPolkadotReceiver::get().into(), + }, + amount: WETH_AMOUNT, + fee: XCM_FEE, + }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); // Check that the send token message was sent using xcm assert_expected_events!( @@ -541,12 +606,13 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { ); // Send the Weth back to Ethereum assert_ok!( - ::PolkadotXcm::reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( RuntimeOrigin::signed(AssetHubPolkadotReceiver::get()), Box::new(destination), Box::new(beneficiary), Box::new(multi_assets), 0, + Unlimited, ) ); @@ -608,9 +674,15 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], )); - // Construct RegisterToken message and sent to inbound queue - let message = todo!(); // FAIL-CI @clara - assert_ok!(send_inbound_message(message)); + let message_id: H256 = [1; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: INSUFFICIENT_XCM_FEE }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); assert_expected_events!( BridgeHubPolkadot, @@ -680,11 +752,84 @@ fn ethereum_sovereign_account() -> AccountId { } fn make_register_token_message() -> InboundQueueFixture { - // FAIL-CI @clara - todo!() -} - -fn make_send_token_message() -> InboundQueueFixture { - // FAIL-CI @clara - todo!() + InboundQueueFixture{ + message: Message { + event_log: Log{ + address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), + topics: vec![ + hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), + hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), + hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), + ], + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e0001000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), + }, + proof: Proof { + receipt_proof: (vec![ + hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(), + ], vec![ + hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e0001000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), + ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("308e4c20194c0c77155c65a2d2c7dcd0ec6a7b20bdeb002c065932149fe0aa1b").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("62d13e9a073dc7cf609005b5531bb208c8686f18f7c8ae02d76232d83ae41a21").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), + ], + } + } + }, + finalized_header: BeaconHeader { + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), + }, + block_roots_root: hex!("3adb5c78afd49ef17160ca7fc38b47228cbb13a317709c86bb6f51d799ba9ab6").into(), + } } diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs b/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs index 9ee140dae1..0796ffc8e6 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/tests/snowbridge.rs @@ -21,40 +21,26 @@ use bridge_hub_kusama_runtime::{ bridge_to_ethereum_config::{EthereumGatewayAddress, EthereumNetwork}, bridge_to_polkadot_config::RefundBridgeHubPolkadotMessages, xcm_config::{XcmConfig, XcmFeeManagerFromComponentsBridgeHub}, - BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic, + AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, + MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, + UncheckedExtrinsic, }; -use bridge_hub_test_utils::ValidatorIdOf; use codec::{Decode, Encode}; -use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; -use frame_support::{ - assert_err, assert_ok, parameter_types, - traits::{Contains, OnFinalize, OnInitialize}, -}; -use frame_system::pallet_prelude::BlockNumberFor; -use kusama_runtime_constants::currency::UNITS; +use cumulus_primitives_core::XcmError::{FailedToTransactAsset, TooExpensive}; +use frame_support::{parameter_types, traits::Contains}; use parachains_common::{AccountId, AuraId, Balance}; pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; -use parachains_runtimes_test_utils::{ - AccountIdOf, CollatorSessionKeys, ExtBuilder, XcmReceivedFrom, -}; -use snowbridge_core::{gwei, meth, ChannelId, ParaId, Rewards}; use snowbridge_pallet_ethereum_client::WeightInfo; -use snowbridge_pallet_system::{PricingParametersOf, WeightInfo as EthereumSystemWeightInfo}; -use snowbridge_runtime_test_common::initial_fund; use sp_core::H160; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, traits::Header, - AccountId32, FixedU128, Saturating, + AccountId32, }; -use xcm::{latest::prelude::*, v3::Error}; +use xcm::latest::prelude::*; use xcm_builder::HandleFee; -use xcm_executor::{ - traits::{FeeManager, FeeReason}, - XcmExecutor, -}; +use xcm_executor::traits::{FeeManager, FeeReason}; type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; @@ -73,7 +59,8 @@ fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys( + snowbridge_runtime_test_common::send_transfer_token_message_success::( + 1, collator_session_keys(), 1013, 1000, @@ -103,7 +90,8 @@ pub fn unpaid_transfer_token_to_ethereum_fails_with_barrier() { #[test] pub fn transfer_token_to_ethereum_fee_not_enough() { - send_transfer_token_message_failure::( + snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 1, collator_session_keys(), 1013, 1000, @@ -111,15 +99,15 @@ pub fn transfer_token_to_ethereum_fee_not_enough() { H160::random(), H160::random(), // fee not enough - 1_000_000_000, - Box::new(|call| RuntimeCall::EthereumSystem(call).encode()), - NotHoldingFees, + 1_000_000, + TooExpensive, ) } #[test] pub fn transfer_token_to_ethereum_insufficient_fund() { - send_transfer_token_message_failure::( + snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 1, collator_session_keys(), 1013, 1000, @@ -127,7 +115,6 @@ pub fn transfer_token_to_ethereum_insufficient_fund() { H160::random(), H160::random(), DefaultBridgeHubEthereumBaseFee::get(), - Box::new(|call| RuntimeCall::EthereumSystem(call).encode()), FailedToTransactAsset("Funds are unavailable"), ) } @@ -202,75 +189,6 @@ impl HandleFee for MockFeeHandler { type TestXcmFeeManager = XcmFeeManagerFromComponentsBridgeHub; -#[allow(clippy::too_many_arguments)] -pub fn send_transfer_token_message_failure( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - assethub_parachain_id: u32, - initial_amount: u128, - weth_contract_address: H160, - destination_address: H160, - fee_amount: u128, - system_call_encode: Box) -> Vec>, - expected_error: Error, -) where - Runtime: bridge_hub_test_utils::BasicParachainRuntime - + snowbridge_pallet_outbound_queue::Config - + snowbridge_pallet_system::Config, - XcmConfig: xcm_executor::Config, - ValidatorIdOf: From>, - <::Token as frame_support::traits::fungible::Inspect<::AccountId>>::Balance: From -{ - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - assert_ok!(>::initialize( - runtime_para_id.into(), - assethub_parachain_id.into(), - )); - - let require_weight_at_most = - ::WeightInfo::set_pricing_parameters(); - - let set_pricing_parameters_call = system_call_encode(snowbridge_pallet_system::Call::< - Runtime, - >::set_pricing_parameters { - params: { - PricingParametersOf:: { - exchange_rate: FixedU128::from_rational(1, 75), - fee_per_gas: gwei(20), - rewards: Rewards { - local: (UNITS / 100).into(), // 0.01 KSM - remote: meth(1), - }, - multiplier: FixedU128::from_rational(1, 1), - } - }, - }); - - assert_ok!(RuntimeHelper::::execute_as_governance( - set_pricing_parameters_call, - require_weight_at_most - ) - .ensure_complete()); - - // fund asset hub sovereign account enough so it can pay fees - initial_fund::(assethub_parachain_id, initial_amount); - - let outcome = send_transfer_token_message::( - assethub_parachain_id, - weth_contract_address, - destination_address, - fee_amount, - ); - assert_err!(outcome.ensure_complete(), expected_error); - }); -} - #[test] fn max_message_queue_service_weight_is_more_than_beacon_extrinsic_weights() { let max_message_queue_weight = MessageQueueServiceWeight::get(); @@ -302,7 +220,25 @@ fn ethereum_to_polkadot_message_extrinsics_work() { #[test] fn ethereum_outbound_queue_processes_messages_before_message_queue_works() { - // TODO: add test after dependencies are upgraded to >= 1.8 + snowbridge_runtime_test_common::ethereum_outbound_queue_processes_messages_before_message_queue_works::< + Runtime, + XcmConfig, + AllPalletsWithoutSystem, + >( + 1, + collator_session_keys(), + 1013, + 1000, + H160::random(), + H160::random(), + DefaultBridgeHubEthereumBaseFee::get(), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event), + _ => None, + } + }), + ) } fn construct_extrinsic( @@ -342,153 +278,3 @@ fn construct_and_apply_extrinsic( let r = Executive::apply_extrinsic(xt); r.unwrap() } - -// TODO remove when Ethereum network ID has been extracted as a param -pub fn send_transfer_token_message( - assethub_parachain_id: u32, - weth_contract_address: H160, - destination_address: H160, - fee_amount: u128, -) -> Outcome -where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + snowbridge_pallet_outbound_queue::Config, - XcmConfig: xcm_executor::Config, -{ - let assethub_parachain_location = Location::new(1, Parachain(assethub_parachain_id)); - let asset = Asset { - id: AssetId(Location::new( - 0, - [AccountKey20 { network: None, key: weth_contract_address.into() }], - )), - fun: Fungible(1000000000), - }; - let assets = vec![asset.clone()]; - - let inner_xcm = Xcm(vec![ - WithdrawAsset(Assets::from(assets.clone())), - ClearOrigin, - BuyExecution { fees: asset, weight_limit: Unlimited }, - DepositAsset { - assets: Wild(All), - beneficiary: Location::new( - 0, - [AccountKey20 { network: None, key: destination_address.into() }], - ), - }, - SetTopic([0; 32]), - ]); - - let fee = - Asset { id: AssetId(Location { parents: 1, interior: Here }), fun: Fungible(fee_amount) }; - - // prepare transfer token message - let xcm = Xcm(vec![ - WithdrawAsset(Assets::from(vec![fee.clone()])), - BuyExecution { fees: fee, weight_limit: Unlimited }, - ExportMessage { network: Ethereum { chain_id: 1 }, destination: Here, xcm: inner_xcm }, - ]); - - // execute XCM - let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); - XcmExecutor::::prepare_and_execute( - assethub_parachain_location, - xcm, - &mut hash, - RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), - Weight::zero(), - ) -} - -pub fn send_transfer_token_message_success( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - assethub_parachain_id: u32, - weth_contract_address: H160, - destination_address: H160, - fee_amount: u128, - snowbridge_pallet_outbound_queue: Box< - dyn Fn(Vec) -> Option>, - >, -) where - Runtime: bridge_hub_test_utils::BasicParachainRuntime - + pallet_message_queue::Config - + snowbridge_pallet_outbound_queue::Config - + snowbridge_pallet_system::Config, - XcmConfig: xcm_executor::Config, - ValidatorIdOf: From>, - ::AccountId: From + AsRef<[u8]>, -{ - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - >::initialize( - runtime_para_id.into(), - assethub_parachain_id.into(), - ) - .unwrap(); - - // fund asset hub sovereign account enough so it can pay fees - initial_fund::(assethub_parachain_id, 5_000_000_000_000); - - let outcome = send_transfer_token_message::( - assethub_parachain_id, - weth_contract_address, - destination_address, - fee_amount, - ); - - assert_ok!(outcome.ensure_complete()); - - // check events - let mut events = >::events() - .into_iter() - .filter_map(|e| snowbridge_pallet_outbound_queue(e.event.encode())); - assert!(events.any(|e| matches!( - e, - snowbridge_pallet_outbound_queue::Event::MessageQueued { .. } - ))); - - let block_number = >::block_number(); - let next_block_number = >::block_number() - .saturating_add(BlockNumberFor::::from(1u32)); - - // finish current block - >::on_finalize(block_number); - >::on_finalize(block_number); - >::on_finalize(block_number); - - // start next block - >::set_block_number(next_block_number); - >::on_initialize(next_block_number); - >::on_initialize(next_block_number); - >::on_initialize(next_block_number); - - // finish next block - >::on_finalize(next_block_number); - >::on_finalize(next_block_number); - let included_head = >::finalize(); - - let origin: ParaId = assethub_parachain_id.into(); - let channel_id: ChannelId = origin.into(); - - let nonce = snowbridge_pallet_outbound_queue::Nonce::::try_get(channel_id); - assert_ok!(nonce); - assert_eq!(nonce.unwrap(), 1); - - let digest = included_head.digest(); - - let digest_items = digest.logs(); - assert!(digest_items.len() == 1 && digest_items[0].as_other().is_some()); - }); -} diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs index 3531d70d38..4bf2af4d03 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/tests/snowbridge.rs @@ -21,40 +21,26 @@ use bridge_hub_polkadot_runtime::{ bridge_to_ethereum_config::{EthereumGatewayAddress, EthereumNetwork}, bridge_to_kusama_config::RefundBridgeHubKusamaMessages, xcm_config::{XcmConfig, XcmFeeManagerFromComponentsBridgeHub}, - BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic, + AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, + MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, + UncheckedExtrinsic, }; -use bridge_hub_test_utils::ValidatorIdOf; use codec::{Decode, Encode}; -use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; -use frame_support::{ - assert_err, assert_ok, parameter_types, - traits::{Contains, OnFinalize, OnInitialize}, -}; -use frame_system::pallet_prelude::BlockNumberFor; +use cumulus_primitives_core::XcmError::{FailedToTransactAsset, TooExpensive}; +use frame_support::{parameter_types, traits::Contains}; use parachains_common::{AccountId, AuraId, Balance}; pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; -use parachains_runtimes_test_utils::{ - AccountIdOf, CollatorSessionKeys, ExtBuilder, XcmReceivedFrom, -}; -use polkadot_runtime_constants::currency::UNITS; -use snowbridge_core::{gwei, meth, ChannelId, ParaId, Rewards}; use snowbridge_pallet_ethereum_client::WeightInfo; -use snowbridge_pallet_system::{PricingParametersOf, WeightInfo as EthereumSystemWeightInfo}; -use snowbridge_runtime_test_common::initial_fund; use sp_core::H160; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, traits::Header, - AccountId32, FixedU128, Saturating, + AccountId32, }; -use xcm::{latest::prelude::*, v3::Error}; +use xcm::latest::prelude::*; use xcm_builder::HandleFee; -use xcm_executor::{ - traits::{FeeManager, FeeReason}, - XcmExecutor, -}; +use xcm_executor::traits::{FeeManager, FeeReason}; type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; @@ -73,7 +59,8 @@ fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys( + snowbridge_runtime_test_common::send_transfer_token_message_success::( + 1, collator_session_keys(), 1013, 1000, @@ -103,7 +90,8 @@ pub fn unpaid_transfer_token_to_ethereum_fails_with_barrier() { #[test] pub fn transfer_token_to_ethereum_fee_not_enough() { - send_transfer_token_message_failure::( + snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 1, collator_session_keys(), 1013, 1000, @@ -111,15 +99,15 @@ pub fn transfer_token_to_ethereum_fee_not_enough() { H160::random(), H160::random(), // fee not enough - 1_000_000_000, - Box::new(|call| RuntimeCall::EthereumSystem(call).encode()), - NotHoldingFees, + 1_000_000, + TooExpensive, ) } #[test] pub fn transfer_token_to_ethereum_insufficient_fund() { - send_transfer_token_message_failure::( + snowbridge_runtime_test_common::send_transfer_token_message_failure::( + 1, collator_session_keys(), 1013, 1000, @@ -127,7 +115,6 @@ pub fn transfer_token_to_ethereum_insufficient_fund() { H160::random(), H160::random(), DefaultBridgeHubEthereumBaseFee::get(), - Box::new(|call| RuntimeCall::EthereumSystem(call).encode()), FailedToTransactAsset("Funds are unavailable"), ) } @@ -202,75 +189,6 @@ impl HandleFee for MockFeeHandler { type TestXcmFeeManager = XcmFeeManagerFromComponentsBridgeHub; -#[allow(clippy::too_many_arguments)] -pub fn send_transfer_token_message_failure( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - assethub_parachain_id: u32, - initial_amount: u128, - weth_contract_address: H160, - destination_address: H160, - fee_amount: u128, - system_call_encode: Box) -> Vec>, - expected_error: Error, -) where - Runtime: bridge_hub_test_utils::BasicParachainRuntime - + snowbridge_pallet_outbound_queue::Config - + snowbridge_pallet_system::Config, - XcmConfig: xcm_executor::Config, - ValidatorIdOf: From>, - <::Token as frame_support::traits::fungible::Inspect<::AccountId>>::Balance: From -{ - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - assert_ok!(>::initialize( - runtime_para_id.into(), - assethub_parachain_id.into(), - )); - - let require_weight_at_most = - ::WeightInfo::set_pricing_parameters(); - - let set_pricing_parameters_call = system_call_encode(snowbridge_pallet_system::Call::< - Runtime, - >::set_pricing_parameters { - params: { - PricingParametersOf:: { - exchange_rate: FixedU128::from_rational(1, 75), - fee_per_gas: gwei(20), - rewards: Rewards { - local: (UNITS / 100).into(), // 0.01 DOT - remote: meth(1), - }, - multiplier: FixedU128::from_rational(1, 1), - } - }, - }); - - assert_ok!(RuntimeHelper::::execute_as_governance( - set_pricing_parameters_call, - require_weight_at_most - ) - .ensure_complete()); - - // fund asset hub sovereign account enough so it can pay fees - initial_fund::(assethub_parachain_id, initial_amount); - - let outcome = send_transfer_token_message::( - assethub_parachain_id, - weth_contract_address, - destination_address, - fee_amount, - ); - assert_err!(outcome.ensure_complete(), expected_error); - }); -} - #[test] fn max_message_queue_service_weight_is_more_than_beacon_extrinsic_weights() { let max_message_queue_weight = MessageQueueServiceWeight::get(); @@ -302,7 +220,25 @@ fn ethereum_to_polkadot_message_extrinsics_work() { #[test] fn ethereum_outbound_queue_processes_messages_before_message_queue_works() { - // TODO: add test after dependencies are upgraded to >= 1.8 + snowbridge_runtime_test_common::ethereum_outbound_queue_processes_messages_before_message_queue_works::< + Runtime, + XcmConfig, + AllPalletsWithoutSystem, + >( + 1, + collator_session_keys(), + 1013, + 1000, + H160::random(), + H160::random(), + DefaultBridgeHubEthereumBaseFee::get(), + Box::new(|runtime_event_encoded: Vec| { + match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { + Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event), + _ => None, + } + }), + ) } fn construct_extrinsic( @@ -342,153 +278,3 @@ fn construct_and_apply_extrinsic( let r = Executive::apply_extrinsic(xt); r.unwrap() } - -// TODO remove when Ethereum network ID has been extracted as a param -pub fn send_transfer_token_message( - assethub_parachain_id: u32, - weth_contract_address: H160, - destination_address: H160, - fee_amount: u128, -) -> Outcome -where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + snowbridge_pallet_outbound_queue::Config, - XcmConfig: xcm_executor::Config, -{ - let assethub_parachain_location = Location::new(1, Parachain(assethub_parachain_id)); - let asset = Asset { - id: AssetId(Location::new( - 0, - [AccountKey20 { network: None, key: weth_contract_address.into() }], - )), - fun: Fungible(1000000000), - }; - let assets = vec![asset.clone()]; - - let inner_xcm = Xcm(vec![ - WithdrawAsset(Assets::from(assets.clone())), - ClearOrigin, - BuyExecution { fees: asset, weight_limit: Unlimited }, - DepositAsset { - assets: Wild(All), - beneficiary: Location::new( - 0, - [AccountKey20 { network: None, key: destination_address.into() }], - ), - }, - SetTopic([0; 32]), - ]); - - let fee = - Asset { id: AssetId(Location { parents: 1, interior: Here }), fun: Fungible(fee_amount) }; - - // prepare transfer token message - let xcm = Xcm(vec![ - WithdrawAsset(Assets::from(vec![fee.clone()])), - BuyExecution { fees: fee, weight_limit: Unlimited }, - ExportMessage { network: Ethereum { chain_id: 1 }, destination: Here, xcm: inner_xcm }, - ]); - - // execute XCM - let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); - XcmExecutor::::prepare_and_execute( - assethub_parachain_location, - xcm, - &mut hash, - RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), - Weight::zero(), - ) -} - -pub fn send_transfer_token_message_success( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - assethub_parachain_id: u32, - weth_contract_address: H160, - destination_address: H160, - fee_amount: u128, - snowbridge_pallet_outbound_queue: Box< - dyn Fn(Vec) -> Option>, - >, -) where - Runtime: bridge_hub_test_utils::BasicParachainRuntime - + pallet_message_queue::Config - + snowbridge_pallet_outbound_queue::Config - + snowbridge_pallet_system::Config, - XcmConfig: xcm_executor::Config, - ValidatorIdOf: From>, - ::AccountId: From + AsRef<[u8]>, -{ - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - >::initialize( - runtime_para_id.into(), - assethub_parachain_id.into(), - ) - .unwrap(); - - // fund asset hub sovereign account enough so it can pay fees - initial_fund::(assethub_parachain_id, 5_000_000_000_000); - - let outcome = send_transfer_token_message::( - assethub_parachain_id, - weth_contract_address, - destination_address, - fee_amount, - ); - - assert_ok!(outcome.ensure_complete()); - - // check events - let mut events = >::events() - .into_iter() - .filter_map(|e| snowbridge_pallet_outbound_queue(e.event.encode())); - assert!(events.any(|e| matches!( - e, - snowbridge_pallet_outbound_queue::Event::MessageQueued { .. } - ))); - - let block_number = >::block_number(); - let next_block_number = >::block_number() - .saturating_add(BlockNumberFor::::from(1u32)); - - // finish current block - >::on_finalize(block_number); - >::on_finalize(block_number); - >::on_finalize(block_number); - - // start next block - >::set_block_number(next_block_number); - >::on_initialize(next_block_number); - >::on_initialize(next_block_number); - >::on_initialize(next_block_number); - - // finish next block - >::on_finalize(next_block_number); - >::on_finalize(next_block_number); - let included_head = >::finalize(); - - let origin: ParaId = assethub_parachain_id.into(); - let channel_id: ChannelId = origin.into(); - - let nonce = snowbridge_pallet_outbound_queue::Nonce::::try_get(channel_id); - assert_ok!(nonce); - assert_eq!(nonce.unwrap(), 1); - - let digest = included_head.digest(); - - let digest_items = digest.logs(); - assert!(digest_items.len() == 1 && digest_items[0].as_other().is_some()); - }); -}