// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use codec::Encode; use frame_support::{assert_err, assert_ok, traits::fungible::Mutate}; pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; use parachains_runtimes_test_utils::{ AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf, XcmReceivedFrom, }; use sp_core::H160; use sp_runtime::SaturatedConversion; use xcm::{ latest::prelude::*, v3::Error::{self, Barrier}, }; use xcm_executor::XcmExecutor; type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; pub fn initial_fund(assethub_parachain_id: u32, initial_amount: u128) where Runtime: frame_system::Config + pallet_balances::Config, { // fund asset hub sovereign account enough so it can pay fees let asset_hub_sovereign_account = snowbridge_core::sibling_sovereign_account::(assethub_parachain_id.into()); >::mint_into( &asset_hub_sovereign_account, initial_amount.saturated_into::>(), ) .unwrap(); } 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: 11155111 }, 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: 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 + snowbridge_pallet_system::Config, XcmConfig: xcm_executor::Config, ValidatorIdOf: 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(|| { >::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 { .. } ))); }); } pub fn send_unpaid_transfer_token_message( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, assethub_parachain_id: u32, weth_contract_address: H160, destination_contract: H160, ) 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, ValidatorIdOf: From>, { let assethub_parachain_location = Location::new(1, Parachain(assethub_parachain_id)); 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(|| { let asset_hub_sovereign_account = snowbridge_core::sibling_sovereign_account::(assethub_parachain_id.into()); >::mint_into( &asset_hub_sovereign_account, 4000000000u32.into(), ) .unwrap(); 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(AllCounted(1)), beneficiary: Location::new( 0, [AccountKey20 { network: None, key: destination_contract.into() }], ), }, SetTopic([0; 32]), ]); // prepare transfer token message let xcm = Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, ExportMessage { network: Ethereum { chain_id: 11155111 }, destination: Here, xcm: inner_xcm, }, ]); // execute XCM let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); let outcome = XcmExecutor::::prepare_and_execute( assethub_parachain_location, xcm, &mut hash, RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), Weight::zero(), ); // check error is barrier assert_err!(outcome.ensure_complete(), Barrier); }); } #[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, expected_error: Error, ) 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 + snowbridge_pallet_system::Config, XcmConfig: xcm_executor::Config, ValidatorIdOf: 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(|| { >::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, initial_amount); let outcome = send_transfer_token_message::( assethub_parachain_id, weth_contract_address, destination_address, fee_amount, ); // check err is NotHoldingFees assert_err!(outcome.ensure_complete(), expected_error); }); }