diff --git a/runtime/amplitude/src/xcm_config.rs b/runtime/amplitude/src/xcm_config.rs index b157fa09a..de13eff70 100644 --- a/runtime/amplitude/src/xcm_config.rs +++ b/runtime/amplitude/src/xcm_config.rs @@ -358,4 +358,4 @@ impl Convert for AccountIdToMultiLocation { impl cumulus_pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; -} \ No newline at end of file +} diff --git a/runtime/common/src/custom_transactor.rs b/runtime/common/src/custom_transactor.rs index b426531eb..65917b6b2 100644 --- a/runtime/common/src/custom_transactor.rs +++ b/runtime/common/src/custom_transactor.rs @@ -1,6 +1,5 @@ - -use sp_runtime::codec::FullCodec; use sp_runtime::{ + codec::FullCodec, traits::{Convert, MaybeSerializeDeserialize, SaturatedConversion}, }; use sp_std::{ @@ -11,108 +10,49 @@ use sp_std::{ result, }; +use orml_xcm_support::{OnDepositFail, UnknownAsset as UnknownAssetT}; use xcm::v3::{prelude::*, Error as XcmError, MultiAsset, MultiLocation, Result}; use xcm_executor::{ traits::{Convert as MoreConvert, MatchesFungible, TransactAsset}, Assets, }; -use orml_xcm_support::{UnknownAsset as UnknownAssetT,OnDepositFail}; - -/// Asset transaction errors. -enum Error { - /// Failed to match fungible. - FailedToMatchFungible, - /// `MultiLocation` to `AccountId` Conversion failed. - AccountIdConversionFailed, - /// `CurrencyId` conversion failed. - CurrencyIdConversionFailed, -} - -impl From for XcmError { - fn from(e: Error) -> Self { - match e { - Error::FailedToMatchFungible => XcmError::FailedToTransactAsset("FailedToMatchFungible"), - Error::AccountIdConversionFailed => XcmError::FailedToTransactAsset("AccountIdConversionFailed"), - Error::CurrencyIdConversionFailed => XcmError::FailedToTransactAsset("CurrencyIdConversionFailed"), - } - } +pub struct AssetData { + pub length: u8, + pub data: [u8; 32], } pub trait AutomationPalletConfig { fn matches_asset(asset: &MultiAsset) -> Option; - fn matches_beneficiary(beneficiary_location: &MultiLocation) -> Option<(u8, [u8;32])>; - fn callback(length: u8, data: [u8;32], amount: u128) -> Result; + fn matches_beneficiary(beneficiary_location: &MultiLocation) -> Option; + fn callback(length: u8, data: [u8; 32], amount: u128) -> Result; } -#[allow(clippy::type_complexity)] -pub struct CustomMultiCurrencyAdapter< - MultiCurrency, - UnknownAsset, - Match, - AccountId, - AccountIdConvert, - CurrencyId, - CurrencyIdConvert, - DepositFailureHandler, - AutomationPalletConfigT, ->( - PhantomData<( - MultiCurrency, - UnknownAsset, - Match, - AccountId, - AccountIdConvert, - CurrencyId, - CurrencyIdConvert, - DepositFailureHandler, - AutomationPalletConfigT, - )>, +pub struct CustomTransactorInterceptor( + PhantomData<(WrappedTransactor, AutomationPalletConfigT)>, ); -impl< - MultiCurrency: orml_traits::MultiCurrency, - UnknownAsset: UnknownAssetT, - Match: MatchesFungible, - AccountId: sp_std::fmt::Debug + Clone, - AccountIdConvert: MoreConvert, - CurrencyId: FullCodec + Eq + PartialEq + Copy + MaybeSerializeDeserialize + Debug, - CurrencyIdConvert: Convert>, - DepositFailureHandler: OnDepositFail, - AutomationPalletConfigT: AutomationPalletConfig - > TransactAsset - for CustomMultiCurrencyAdapter< - MultiCurrency, - UnknownAsset, - Match, - AccountId, - AccountIdConvert, - CurrencyId, - CurrencyIdConvert, - DepositFailureHandler, - AutomationPalletConfigT, - > +impl + TransactAsset for CustomTransactorInterceptor { - fn deposit_asset(asset: &MultiAsset, location: &MultiLocation, _context: &XcmContext) -> Result { - - if let (Some(amount_deposited), Some((length, data))) = - (AutomationPalletConfigT::matches_asset(asset), AutomationPalletConfigT::matches_beneficiary(location)) { - AutomationPalletConfigT::callback(length, data, amount_deposited); - return Ok(()); - } - - match ( - AccountIdConvert::convert_ref(location), - CurrencyIdConvert::convert(asset.clone()), - Match::matches_fungible(asset), + fn deposit_asset( + asset: &MultiAsset, + location: &MultiLocation, + _context: &XcmContext, + ) -> Result { + if let (Some(amount_deposited), Some(asset_data)) = ( + AutomationPalletConfigT::matches_asset(asset), + AutomationPalletConfigT::matches_beneficiary(location), ) { - // known asset - (Ok(who), Some(currency_id), Some(amount)) => MultiCurrency::deposit(currency_id, &who, amount) - .or_else(|err| DepositFailureHandler::on_deposit_currency_fail(err, currency_id, &who, amount)), - // unknown asset - _ => UnknownAsset::deposit(asset, location) - .or_else(|err| DepositFailureHandler::on_deposit_unknown_asset_fail(err, asset, location)), + AutomationPalletConfigT::callback( + asset_data.length, + asset_data.data, + amount_deposited, + )?; + return Ok(()) } + + WrappedTransactor::deposit_asset(asset, location, _context) } fn withdraw_asset( @@ -120,18 +60,7 @@ impl< location: &MultiLocation, _maybe_context: Option<&XcmContext>, ) -> result::Result { - UnknownAsset::withdraw(asset, location).or_else(|_| { - let who = AccountIdConvert::convert_ref(location) - .map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; - let currency_id = CurrencyIdConvert::convert(asset.clone()) - .ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?; - let amount: MultiCurrency::Balance = Match::matches_fungible(asset) - .ok_or_else(|| XcmError::from(Error::FailedToMatchFungible))? - .saturated_into(); - MultiCurrency::withdraw(currency_id, &who, amount).map_err(|e| XcmError::FailedToTransactAsset(e.into())) - })?; - - Ok(asset.clone().into()) + WrappedTransactor::withdraw_asset(asset, location, _maybe_context) } fn transfer_asset( @@ -140,19 +69,6 @@ impl< to: &MultiLocation, _context: &XcmContext, ) -> result::Result { - let from_account = - AccountIdConvert::convert_ref(from).map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; - let to_account = - AccountIdConvert::convert_ref(to).map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?; - let currency_id = CurrencyIdConvert::convert(asset.clone()) - .ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?; - let amount: MultiCurrency::Balance = Match::matches_fungible(asset) - .ok_or_else(|| XcmError::from(Error::FailedToMatchFungible))? - .saturated_into(); - MultiCurrency::transfer(currency_id, &from_account, &to_account, amount) - .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; - - Ok(asset.clone().into()) + WrappedTransactor::transfer_asset(asset, from, to, _context) } } - diff --git a/runtime/foucoco/src/xcm_config.rs b/runtime/foucoco/src/xcm_config.rs index 4be8677a6..18425d58a 100644 --- a/runtime/foucoco/src/xcm_config.rs +++ b/runtime/foucoco/src/xcm_config.rs @@ -357,4 +357,4 @@ impl Convert for AccountIdToMultiLocation { impl cumulus_pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; -} \ No newline at end of file +} diff --git a/runtime/integration-tests/src/mock.rs b/runtime/integration-tests/src/mock.rs index 1d1add86b..eb6a36b6b 100644 --- a/runtime/integration-tests/src/mock.rs +++ b/runtime/integration-tests/src/mock.rs @@ -117,7 +117,7 @@ pub enum ParachainType { Pendulum, Amplitude, Sibling, - Moonbeam + Moonbeam, } pub struct ExtBuilderParachain { @@ -191,8 +191,7 @@ pub fn para_ext(chain: ParachainType) -> sp_io::TestExternalities { ParachainType::Amplitude => ExtBuilderParachain::amplitude_default().balances(vec![]).build(), ParachainType::Sibling => ExtBuilderParachain::sibling_default().balances(vec![]).build(), - ParachainType::Moonbeam => - ExtBuilderParachain::moonbeam_default().balances(vec![]).build(), + ParachainType::Moonbeam => ExtBuilderParachain::moonbeam_default().balances(vec![]).build(), } } diff --git a/runtime/integration-tests/src/pendulum_tests.rs b/runtime/integration-tests/src/pendulum_tests.rs index 0f4118e29..01b189592 100644 --- a/runtime/integration-tests/src/pendulum_tests.rs +++ b/runtime/integration-tests/src/pendulum_tests.rs @@ -2,21 +2,21 @@ use crate::{ mock::{para_ext, polkadot_relay_ext, ParachainType, USDT_ASSET_ID}, sibling, test_macros::{ - parachain1_transfer_asset_to_parachain2, parachain1_transfer_asset_to_parachain2_and_back, + moonbeam_transfers_token_and_handle_automation, parachain1_transfer_asset_to_parachain2, + parachain1_transfer_asset_to_parachain2_and_back, parachain1_transfer_incorrect_asset_to_parachain2_should_fail, transfer_10_relay_token_from_parachain_to_relay_chain, transfer_20_relay_token_from_relay_chain_to_parachain, transfer_native_token_from_parachain1_to_parachain2_and_back, - moonbeam_transfers_token_and_handle_automation }, ASSETHUB_ID, PENDULUM_ID, SIBLING_ID, }; use frame_support::assert_ok; +use runtime_common::parachains::polkadot::moonbeam::PARA_ID as MOONBEAM_PARA_ID; use statemint_runtime as polkadot_asset_hub_runtime; use xcm::latest::NetworkId; use xcm_emulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; -use runtime_common::parachains::polkadot::moonbeam::PARA_ID as MOONBEAM_PARA_ID; const DOT_FEE_WHEN_TRANSFER_TO_PARACHAIN: polkadot_core_primitives::Balance = 3200000000; //The fees that relay chain will charge when transfer DOT to parachain. sovereign account of some parachain will receive transfer_amount - DOT_FEE diff --git a/runtime/integration-tests/src/test_macros.rs b/runtime/integration-tests/src/test_macros.rs index fff87474e..85e713bff 100644 --- a/runtime/integration-tests/src/test_macros.rs +++ b/runtime/integration-tests/src/test_macros.rs @@ -619,7 +619,6 @@ macro_rules! moonbeam_transfers_token_and_handle_automation { ) => {{ use crate::mock::{units, ALICE}; use polkadot_core_primitives::Balance; - use xcm::latest::{ Junction, Junction::{ GeneralKey, PalletInstance}, Junctions::{X1,X2, X3}, MultiLocation, WeightLimit, }; diff --git a/runtime/pendulum/src/xcm_config.rs b/runtime/pendulum/src/xcm_config.rs index d42b6d774..67278aba6 100644 --- a/runtime/pendulum/src/xcm_config.rs +++ b/runtime/pendulum/src/xcm_config.rs @@ -6,22 +6,23 @@ use frame_support::{ }; use orml_traits::{ location::{RelativeReserveProvider, Reserve}, - parameter_type_with_key,}; + parameter_type_with_key, +}; use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter}; use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; -use sp_runtime::{traits::Convert}; +use sp_runtime::traits::Convert; use xcm::latest::{prelude::*, Weight as XCMWeight}; use xcm_builder::{ - AccountId32Aliases, EnsureXcmOrigin, FixedWeightBounds,AllowUnpaidExecutionFrom, + AccountId32Aliases, AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, UsingComponents, }; use xcm_executor::{traits::ShouldExecute, XcmExecutor}; use runtime_common::{ - custom_transactor::{CustomMultiCurrencyAdapter, AutomationPalletConfig}, + custom_transactor::{AssetData, AutomationPalletConfig, CustomTransactorInterceptor}, parachains::polkadot::{asset_hub, equilibrium, moonbeam, polkadex}, }; @@ -40,10 +41,9 @@ use crate::{ use super::{ AccountId, Balance, Balances, Currencies, CurrencyId, ParachainInfo, ParachainSystem, PendulumTreasuryAccount, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - WeightToFee, XcmpQueue, Treasury, System + System, Treasury, WeightToFee, XcmpQueue, }; - parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: NetworkId = NetworkId::Polkadot; @@ -53,6 +53,9 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); } +/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. pub type LocationToAccountId = ( // The parent (Relay-chain) origin converts to the parent `AccountId`. ParentIsPreset, @@ -150,8 +153,6 @@ where } } - - /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, /// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can /// biases the kind of local `Origin` it will become. @@ -260,36 +261,37 @@ impl AutomationPalletConfig for AutomationPalletConfigPendulum { let expected_multiloc = moonbeam::BRZ_location(); match asset { - MultiAsset { id: AssetId::Concrete(loc), fun: Fungibility::Fungible(amount_deposited) } if loc == &expected_multiloc => - return Some(*amount_deposited), + MultiAsset { + id: AssetId::Concrete(loc), + fun: Fungibility::Fungible(amount_deposited), + } if loc == &expected_multiloc => return Some(*amount_deposited), _ => return None, } } // TODO modify with automation's pallet instance - fn matches_beneficiary(beneficiary_location: &MultiLocation) -> Option<(u8, [u8;32])> { - if let - MultiLocation { - parents: 0, - interior: X2(PalletInstance(99), GeneralKey { length, data }), - } - = beneficiary_location + fn matches_beneficiary(beneficiary_location: &MultiLocation) -> Option { + if let MultiLocation { + parents: 0, + interior: X2(PalletInstance(99), GeneralKey { length, data }), + } = beneficiary_location { - Some((*length, *data)) + let asset_data = AssetData { length: *length, data: *data }; + Some(asset_data) } else { None } } - fn callback(_length: u8, _data: [u8;32], _amount: u128) -> Result<(), XcmError> { + fn callback(_length: u8, _data: [u8; 32], _amount: u128) -> Result<(), XcmError> { // TODO change to call the actual automation pallet, with data and length System::remark_with_event(RuntimeOrigin::signed(AccountId::from([0; 32])), [0; 1].to_vec()); Ok(()) } - } + /// Means for transacting the currencies of this parachain -pub type LocalAssetTransactor = CustomMultiCurrencyAdapter< +type Transactor = MultiCurrencyAdapter< Currencies, (), // We don't handle unknown assets. IsNativeConcrete, @@ -298,8 +300,10 @@ pub type LocalAssetTransactor = CustomMultiCurrencyAdapter< CurrencyId, CurrencyIdConvert, DepositToAlternative, - AutomationPalletConfigPendulum, >; + +pub type LocalAssetTransactor = + CustomTransactorInterceptor; pub type Barrier = AllowUnpaidExecutionFrom; pub struct XcmConfig; @@ -414,4 +418,4 @@ impl Convert for AccountIdToMultiLocation { impl cumulus_pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; -} \ No newline at end of file +}