From 66ba73fd6ebe07015b68673e3507467bbeddba4c Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 2 Feb 2024 18:43:34 +0800 Subject: [PATCH 1/3] Xcm config for weth from asset hub --- runtime/src/xcm_config.rs | 111 +++++++++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 7 deletions(-) diff --git a/runtime/src/xcm_config.rs b/runtime/src/xcm_config.rs index d407292..c01dd28 100644 --- a/runtime/src/xcm_config.rs +++ b/runtime/src/xcm_config.rs @@ -1,17 +1,27 @@ use super::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, AssetLocation, AssetRegistry, Balance, Balances, Currencies, + NativeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeOrigin, WeightToFee, XcmpQueue, }; use frame_support::{ + pallet_prelude::Get, parameter_types, - traits::{ConstU32, Contains, Everything, Nothing}, + traits::{ConstU32, Contains, ContainsPair, Everything, Nothing}, weights::Weight, + PalletId, }; use frame_system::EnsureRoot; +use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter}; use pallet_xcm::XcmPassthrough; +use parachains_common::impls::AssetsFrom; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; -use xcm::latest::prelude::*; +use sp_runtime::traits::{AccountIdConversion, Convert}; +use std::marker::PhantomData; +use xcm::prelude::{ + Asset, AssetId, BodyId, Ethereum, Fungible, GeneralIndex, GlobalConsensus, InteriorLocation, + Location, NetworkId, PalletInstance, Parachain, Parent, Plurality, +}; #[allow(deprecated)] use xcm_builder::CurrencyAdapter; use xcm_builder::{ @@ -111,14 +121,101 @@ pub type Barrier = TrailingSetTopicAsId< >, >; +parameter_types! { + pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub SystemAssetHubAssetsPalletLocation: Location = + Location::new(1, [Parachain(1000), PalletInstance(50)]); + pub AssetsPalletLocation: Location = + Location::new(0, [PalletInstance(50)]); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub EthereumLocation: Location = Location::new(2, [GlobalConsensus(Ethereum { chain_id: 11155111 })]); + pub TreasuryAccount: AccountId = PalletId(*b"py/trsry").into_account_truncating(); +} + +/// Asset filter that allows native/relay asset if coming from a certain location. +pub struct NativeAssetFrom(PhantomData); +impl> ContainsPair for NativeAssetFrom { + fn contains(asset: &Asset, origin: &Location) -> bool { + let loc = T::get(); + &loc == origin && + matches!(asset, Asset { id: xcm::prelude::AssetId(asset_loc), fun: Fungible(_a) } + if *asset_loc == Location::from(Parent)) + } +} + +/// Asset filter that allows all assets from a certain location matching asset id. +pub struct AssetPrefixFrom(PhantomData<(Prefix, Origin)>); +impl ContainsPair for AssetPrefixFrom +where + Prefix: Get, + Origin: Get, +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + let loc = Origin::get(); + &loc == origin && + matches!(asset, Asset { id: AssetId(asset_loc), fun: Fungible(_a) } + if asset_loc.starts_with(&Prefix::get())) + } +} + +pub type Reserves = ( + NativeAsset, + AssetsFrom, + NativeAssetFrom, + AssetPrefixFrom, +); + +pub type CurrencyId = primitives::AssetId; + +pub struct CurrencyIdConvert; + +impl Convert> for CurrencyIdConvert { + fn convert(id: CurrencyId) -> Option { + match id { + id if id == NativeAssetId::get() => Some(Location::new(0, [GeneralIndex(id.into())])), + _ => AssetRegistry::asset_to_location(id).map(|loc| loc.0), + } + } +} + +impl Convert> for CurrencyIdConvert { + fn convert(location: Location) -> Option { + match location.unpack() { + (0, [GeneralIndex(index)]) if (*index as u32) == NativeAssetId::get() => + Some(*index as CurrencyId), + _ => AssetRegistry::location_to_asset(AssetLocation(location)), + } + } +} + +impl Convert> for CurrencyIdConvert { + fn convert(asset: Asset) -> Option { + Self::convert(asset.id.0) + } +} + +pub type AssetTransactor = ( + MultiCurrencyAdapter< + Currencies, + (), + IsNativeConcrete, + AccountId, + LocationToAccountId, + CurrencyId, + CurrencyIdConvert, + DepositToAlternative, + >, + LocalAssetTransactor, +); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; // How to withdraw and deposit an asset. - type AssetTransactor = LocalAssetTransactor; + type AssetTransactor = AssetTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = NativeAsset; + type IsReserve = Reserves; type IsTeleporter = (); // Teleporting is disabled. type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -163,7 +260,7 @@ impl pallet_xcm::Config for Runtime { // Needs to be `Everything` for local testing. type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; + type XcmReserveTransferFilter = Everything; type Weigher = FixedWeightBounds; type UniversalLocation = UniversalLocation; type RuntimeOrigin = RuntimeOrigin; From effffe44ef92548ec65c8d4500f1f882ffe6631f Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 2 Feb 2024 22:26:46 +0800 Subject: [PATCH 2/3] Improve tests --- .../chains/parachains/testing/orml/src/lib.rs | 3 +- .../bridge-hub-rococo/src/tests/snowbridge.rs | 55 ++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/integration-tests/emulated/chains/parachains/testing/orml/src/lib.rs b/integration-tests/emulated/chains/parachains/testing/orml/src/lib.rs index b26b1c4..64b37b8 100644 --- a/integration-tests/emulated/chains/parachains/testing/orml/src/lib.rs +++ b/integration-tests/emulated/chains/parachains/testing/orml/src/lib.rs @@ -23,7 +23,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; // Penpal Parachain declaration @@ -52,3 +52,4 @@ decl_test_parachains! { // Penpal implementation impl_accounts_helpers_for_parachain!(OrmlTemplate); impl_assert_events_helpers_for_parachain!(OrmlTemplate); +impl_xcm_helpers_for_parachain!(OrmlTemplate); diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 4e2f6cd..dd56d45 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -544,6 +544,13 @@ fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() { #[test] fn send_token_from_ethereum_to_orml_chain() { + AssetHubRococo::force_default_xcm_version(Some(XCM_VERSION)); + BridgeHubRococo::force_default_xcm_version(Some(XCM_VERSION)); + OrmlTemplatePara::force_default_xcm_version(Some(XCM_VERSION)); + AssetHubRococo::force_xcm_version( + Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]), + XCM_VERSION, + ); let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( 1, [Parachain(AssetHubRococo::para_id().into())], @@ -551,7 +558,7 @@ fn send_token_from_ethereum_to_orml_chain() { // Fund AssetHub sovereign account so it can pay execution fees for the asset transfer BridgeHubRococo::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); - // Fund PenPal sender and receiver + // Fund sender and receiver on OrmlTemplate chain OrmlTemplatePara::fund_accounts(vec![ (OrmlReceiver::get(), INITIAL_FUND), (OrmlSender::get(), INITIAL_FUND), @@ -567,6 +574,7 @@ fn send_token_from_ethereum_to_orml_chain() { let ethereum_sovereign: AccountId = GlobalConsensusEthereumConvertsFor::::convert_location(&origin_location) .unwrap(); + // Fund ORML sovereign on AssetHub let orml_sovereign_on_asset_hub = AssetHubRococo::sovereign_account_id_of(Location::new( 1, [Parachain(OrmlTemplatePara::para_id().into())], @@ -576,7 +584,7 @@ fn send_token_from_ethereum_to_orml_chain() { (orml_sovereign_on_asset_hub.clone(), INITIAL_FUND), ]); - // Register asset location on the Orml parachain. + // Register WETH and ROC(as fee asset) on OrmlTemplate chain. OrmlTemplatePara::execute_with(|| { use parachain_orml_template_runtime::{AssetRegistry, RuntimeOrigin}; use primitives::{ROC, WETH}; @@ -655,7 +663,7 @@ fn send_token_from_ethereum_to_orml_chain() { &OrmlReceiver::get(), ); assert_eq!(free_balance, WETH_AMOUNT); - // Send the Weth back to Ethereum + // Send the Weth back to AssetHub, with ROC as fee asset let fee_asset = Asset { id: AssetId(Parent.into()), fun: Fungible(XCM_FEE) }; let weth_asset = Asset { id: AssetId(Location::new( @@ -698,6 +706,7 @@ fn send_token_from_ethereum_to_orml_chain() { AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; + type RuntimeOrigin = ::RuntimeOrigin; // Check that weth was burned from orml-sovereign account on AssetHub // and issued into the destination account assert_expected_events!( @@ -711,5 +720,45 @@ fn send_token_from_ethereum_to_orml_chain() { }, ] ); + // Send the WETH back from AssetHub to Ethereum + let assets = vec![Asset { + id: AssetId(Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { network: None, key: WETH }, + ], + )), + fun: Fungible(WETH_AMOUNT), + }]; + let multi_assets = VersionedAssets::V4(Assets::from(assets)); + let destination = VersionedLocation::V4(Location::new( + 2, + [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], + )); + let beneficiary = VersionedLocation::V4(Location::new( + 0, + [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], + )); + ::PolkadotXcm::reserve_transfer_assets( + RuntimeOrigin::signed(AssetHubRococoReceiver::get()), + Box::new(destination), + Box::new(beneficiary), + Box::new(multi_assets), + 0, + ) + .unwrap(); + }); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + // Check that the transfer token back to Ethereum message was queue in the Ethereum + // Outbound Queue + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued {..}) => {}, + ] + ); }); } From cc5df6a01b757b05fa163d98d5048e7d753316d5 Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 2 Feb 2024 23:16:46 +0800 Subject: [PATCH 3/3] Suppress warning/error --- orml/tokens/src/mock.rs | 7 +------ orml/traits/src/asset_registry.rs | 4 ++-- runtime/src/xcm_config.rs | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/orml/tokens/src/mock.rs b/orml/tokens/src/mock.rs index 6824c58..736dcdd 100644 --- a/orml/tokens/src/mock.rs +++ b/orml/tokens/src/mock.rs @@ -5,10 +5,7 @@ use super::*; use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{ - tokens::{PayFromAccount, UnityAssetBalanceConversion}, - ChangeMembers, ConstU32, ConstU64, ContainsLengthBound, Everything, SortedMembers, - }, + traits::{ChangeMembers, ConstU32, ConstU64, ContainsLengthBound, Everything, SortedMembers}, PalletId, }; use orml_traits::parameter_type_with_key; @@ -31,10 +28,8 @@ pub const ALICE: AccountId = AccountId32::new([0u8; 32]); pub const BOB: AccountId = AccountId32::new([1u8; 32]); pub const CHARLIE: AccountId = AccountId32::new([2u8; 32]); pub const DAVE: AccountId = AccountId32::new([3u8; 32]); -pub const TREASURY_ACCOUNT: AccountId = AccountId32::new([4u8; 32]); pub const ID_1: LockIdentifier = *b"1 "; pub const ID_2: LockIdentifier = *b"2 "; -pub const ID_3: LockIdentifier = *b"3 "; pub const RID_1: ReserveIdentifier = [1u8; 8]; pub const RID_2: ReserveIdentifier = [2u8; 8]; diff --git a/orml/traits/src/asset_registry.rs b/orml/traits/src/asset_registry.rs index 56ddee9..33709e4 100644 --- a/orml/traits/src/asset_registry.rs +++ b/orml/traits/src/asset_registry.rs @@ -1,6 +1,7 @@ use frame_support::pallet_prelude::*; use sp_runtime::DispatchResult; use sp_std::fmt::Debug; +use xcm::VersionedLocation; #[allow(deprecated)] use xcm::{v3::prelude::*, VersionedMultiLocation}; @@ -46,8 +47,7 @@ where pub name: BoundedVec, pub symbol: BoundedVec, pub existential_deposit: Balance, - #[allow(deprecated)] - pub location: Option, + pub location: Option, pub additional: CustomMetadata, } #[allow(deprecated)] diff --git a/runtime/src/xcm_config.rs b/runtime/src/xcm_config.rs index c01dd28..51db6bb 100644 --- a/runtime/src/xcm_config.rs +++ b/runtime/src/xcm_config.rs @@ -17,7 +17,7 @@ use parachains_common::impls::AssetsFrom; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; use sp_runtime::traits::{AccountIdConversion, Convert}; -use std::marker::PhantomData; +use sp_std::marker::PhantomData; use xcm::prelude::{ Asset, AssetId, BodyId, Ethereum, Fungible, GeneralIndex, GlobalConsensus, InteriorLocation, Location, NetworkId, PalletInstance, Parachain, Parent, Plurality,