Skip to content

Commit

Permalink
refactor to use MultiCurrencyAdapter as a wrapped AssetTransactor
Browse files Browse the repository at this point in the history
  • Loading branch information
gianfra-t committed Dec 21, 2023
1 parent 7967cbf commit e1f1ee0
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 145 deletions.
2 changes: 1 addition & 1 deletion runtime/amplitude/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,4 +358,4 @@ impl Convert<AccountId, MultiLocation> for AccountIdToMultiLocation {
impl cumulus_pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>;
}
}
142 changes: 29 additions & 113 deletions runtime/common/src/custom_transactor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

use sp_runtime::codec::FullCodec;
use sp_runtime::{
codec::FullCodec,
traits::{Convert, MaybeSerializeDeserialize, SaturatedConversion},
};
use sp_std::{
Expand All @@ -11,127 +10,57 @@ 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<Error> 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<u128>;
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<AssetData>;
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<WrappedTransactor, AutomationPalletConfigT>(
PhantomData<(WrappedTransactor, AutomationPalletConfigT)>,
);

impl<
MultiCurrency: orml_traits::MultiCurrency<AccountId, CurrencyId = CurrencyId>,
UnknownAsset: UnknownAssetT,
Match: MatchesFungible<MultiCurrency::Balance>,
AccountId: sp_std::fmt::Debug + Clone,
AccountIdConvert: MoreConvert<MultiLocation, AccountId>,
CurrencyId: FullCodec + Eq + PartialEq + Copy + MaybeSerializeDeserialize + Debug,
CurrencyIdConvert: Convert<MultiAsset, Option<CurrencyId>>,
DepositFailureHandler: OnDepositFail<CurrencyId, AccountId, MultiCurrency::Balance>,
AutomationPalletConfigT: AutomationPalletConfig
> TransactAsset
for CustomMultiCurrencyAdapter<
MultiCurrency,
UnknownAsset,
Match,
AccountId,
AccountIdConvert,
CurrencyId,
CurrencyIdConvert,
DepositFailureHandler,
AutomationPalletConfigT,
>
impl<WrappedTransactor: TransactAsset, AutomationPalletConfigT: AutomationPalletConfig>
TransactAsset for CustomTransactorInterceptor<WrappedTransactor, AutomationPalletConfigT>
{
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(
asset: &MultiAsset,
location: &MultiLocation,
_maybe_context: Option<&XcmContext>,
) -> result::Result<Assets, XcmError> {
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(
Expand All @@ -140,19 +69,6 @@ impl<
to: &MultiLocation,
_context: &XcmContext,
) -> result::Result<Assets, XcmError> {
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)
}
}

2 changes: 1 addition & 1 deletion runtime/foucoco/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,4 @@ impl Convert<AccountId, MultiLocation> for AccountIdToMultiLocation {
impl cumulus_pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>;
}
}
5 changes: 2 additions & 3 deletions runtime/integration-tests/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub enum ParachainType {
Pendulum,
Amplitude,
Sibling,
Moonbeam
Moonbeam,
}

pub struct ExtBuilderParachain<Currency> {
Expand Down Expand Up @@ -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(),
}
}

Expand Down
6 changes: 3 additions & 3 deletions runtime/integration-tests/src/pendulum_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 0 additions & 1 deletion runtime/integration-tests/src/test_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down
50 changes: 27 additions & 23 deletions runtime/pendulum/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};

Expand All @@ -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;
Expand All @@ -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<AccountId>,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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<AssetData> {
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<CurrencyId, CurrencyIdConvert>,
Expand All @@ -298,8 +300,10 @@ pub type LocalAssetTransactor = CustomMultiCurrencyAdapter<
CurrencyId,
CurrencyIdConvert,
DepositToAlternative<PendulumTreasuryAccount, Currencies, CurrencyId, AccountId, Balance>,
AutomationPalletConfigPendulum,
>;

pub type LocalAssetTransactor =
CustomTransactorInterceptor<Transactor, AutomationPalletConfigPendulum>;
pub type Barrier = AllowUnpaidExecutionFrom<Everything>;

pub struct XcmConfig;
Expand Down Expand Up @@ -414,4 +418,4 @@ impl Convert<AccountId, MultiLocation> for AccountIdToMultiLocation {
impl cumulus_pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>;
}
}

0 comments on commit e1f1ee0

Please sign in to comment.