Skip to content
Open
77 changes: 76 additions & 1 deletion xcm-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@
#![allow(clippy::unused_unit)]

use frame_support::dispatch::{DispatchError, DispatchResult};
use frame_support::{ensure, traits::Contains, weights::Weight};

use sp_runtime::traits::{CheckedConversion, Convert};
use sp_std::{convert::TryFrom, marker::PhantomData, prelude::*};

use xcm::latest::prelude::*;
use xcm_executor::traits::{FilterAssetLocation, MatchesFungible};
use xcm_executor::traits::{FilterAssetLocation, MatchesFungible, ShouldExecute};

use orml_traits::location::Reserve;

pub use currency_adapter::MultiCurrencyAdapter;
use frame_support::pallet_prelude::Get;

mod currency_adapter;

Expand Down Expand Up @@ -75,3 +78,75 @@ impl UnknownAsset for () {
Err(DispatchError::Other(NO_UNKNOWN_ASSET_IMPL))
}
}

/// Extracts the `AccountId32` from the passed `location` if the network
/// matches.
pub struct RelaychainAccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
xcm_executor::traits::Convert<MultiLocation, AccountId> for RelaychainAccountId32Aliases<Network, AccountId>
{
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
let id = match location {
MultiLocation {
parents: 1,
interior: X1(AccountId32 {
id,
network: NetworkId::Any,
}),
} => id,
_ => return Err(location),
};
Ok(id.into())
}

fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> {
Ok(AccountId32 {
id: who.into(),
network: Network::get(),
}
.into())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will reverse to MultiLocation { parents: 0, interior: X1(AccountId32), }, no?
That means it will not convert back to the input if calling RelaychainAccountId32Aliases.convert(location).reverse() which would be desirable, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good point, as the reverse path is not currently go through, I may miss here.

Copy link
Contributor Author

@zqhxuyuan zqhxuyuan Nov 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after I change here to return (1, AccountId32).into(). If we config (...,AccountId32Aliases,RelaychainAccountId32Aliases), then reverse on AccountId will always return (parents:0, X1(AccountId32)). But when I change the order to (...,RelaychainAccountId32Aliases, AccountId32Aliases), then reverse on AccountId will always return (parents:1, X1(AccountId32)). this sounds no better solution if those two config has same trait bounds, unless we make them different.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've post an issue on polkadot: paritytech/polkadot#4296. would you mind to see if that's a potential problem? @KiChjang @apopiak

}
}

pub struct AllowDescendOrigin<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowDescendOrigin<T> {
fn should_execute<Call>(
origin: &MultiLocation,
message: &mut Xcm<Call>,
max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
ensure!(T::contains(origin), ());
let mut iter = message.0.iter_mut();
let i = iter.next().ok_or(())?;
match i {
DescendOrigin(..) => (),
_ => return Err(()),
}
let i = iter.next().ok_or(())?;
match i {
ReceiveTeleportedAsset(..) | WithdrawAsset(..) | ReserveAssetDeposited(..) | ClaimAsset { .. } => (),
_ => return Err(()),
}
let mut i = iter.next().ok_or(())?;
while let ClearOrigin = i {
i = iter.next().ok_or(())?;
}
match i {
BuyExecution {
weight_limit: Limited(ref mut weight),
..
} if *weight >= max_weight => {
*weight = max_weight;
Ok(())
}
BuyExecution {
ref mut weight_limit, ..
} if weight_limit == &Unlimited => {
*weight_limit = Limited(max_weight);
Ok(())
}
_ => Err(()),
}
}
}
2 changes: 2 additions & 0 deletions xtokens/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ xcm-simulator = { git = "https://github.com/paritytech/polkadot", branch = "rele
orml-tokens = { path = "../tokens" }
orml-xcm = { path = "../xcm" }

env_logger = "0.8.3"

[features]
default = ["std"]
std = [
Expand Down
41 changes: 37 additions & 4 deletions xtokens/src/mock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,41 @@ use serde::{Deserialize, Serialize};
use sp_io::TestExternalities;
use sp_runtime::AccountId32;

use cumulus_primitives_core::ParaId;
use polkadot_parachain::primitives::{AccountIdConversion, Sibling};
use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain};

pub mod para;
pub mod relay;
pub mod tests;

pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]);
pub const BOB: AccountId32 = AccountId32::new([1u8; 32]);
pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);
pub const BOB: AccountId32 = AccountId32::new([2u8; 32]);
pub const DEFAULT: AccountId32 = AccountId32::new([0u8; 32]);
pub const INITIAL_BALANCE: u128 = 1_000;

pub fn para_a_account() -> AccountId32 {
ParaId::from(1).into_account()
}

pub fn para_b_account() -> AccountId32 {
ParaId::from(2).into_account()
}

pub fn sibling_a_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(1).into_account()
}

pub fn sibling_b_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(2).into_account()
}

pub fn sibling_c_account() -> AccountId32 {
use sp_runtime::traits::AccountIdConversion;
Sibling::from(3).into_account()
}

#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, PartialOrd, Ord, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
Expand Down Expand Up @@ -118,9 +146,14 @@ decl_test_network! {
}

pub type RelayBalances = pallet_balances::Pallet<relay::Runtime>;
pub type ParaBalances = pallet_balances::Pallet<para::Runtime>;

pub type ParaTokens = orml_tokens::Pallet<para::Runtime>;
pub type ParaXTokens = orml_xtokens::Pallet<para::Runtime>;

pub type RelayChainPalletXcm = pallet_xcm::Pallet<relay::Runtime>;
pub type ParachainPalletXcm = pallet_xcm::Pallet<para::Runtime>;

pub fn para_ext(para_id: u32) -> TestExternalities {
use para::{Runtime, System};

Expand All @@ -135,7 +168,7 @@ pub fn para_ext(para_id: u32) -> TestExternalities {
.unwrap();

orml_tokens::GenesisConfig::<Runtime> {
balances: vec![(ALICE, CurrencyId::R, 1_000)],
balances: vec![(ALICE, CurrencyId::R, INITIAL_BALANCE)],
}
.assimilate_storage(&mut t)
.unwrap();
Expand All @@ -153,7 +186,7 @@ pub fn relay_ext() -> sp_io::TestExternalities {
.unwrap();

pallet_balances::GenesisConfig::<Runtime> {
balances: vec![(ALICE, 1_000)],
balances: vec![(ALICE, INITIAL_BALANCE)],
}
.assimilate_storage(&mut t)
.unwrap();
Expand Down
11 changes: 9 additions & 2 deletions xtokens/src/mock/para.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use xcm_builder::{
use xcm_executor::{traits::WeightTrader, Assets, Config, XcmExecutor};

use orml_traits::parameter_type_with_key;
use orml_xcm_support::{IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset};
use orml_xcm_support::{
AllowDescendOrigin, IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset, RelaychainAccountId32Aliases,
};

pub type AccountId = AccountId32;

Expand Down Expand Up @@ -114,6 +116,7 @@ pub type LocationToAccountId = (
ParentIsDefault<AccountId>,
SiblingParachainConvertsVia<Sibling, AccountId>,
AccountId32Aliases<RelayNetwork, AccountId>,
RelaychainAccountId32Aliases<RelayNetwork, AccountId>,
);

pub type XcmOriginToCallOrigin = (
Expand All @@ -140,7 +143,11 @@ pub type LocalAssetTransactor = MultiCurrencyAdapter<
>;

pub type XcmRouter = ParachainXcmRouter<ParachainInfo>;
pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom<Everything>);
pub type Barrier = (
TakeWeightCredit,
AllowTopLevelPaidExecutionFrom<Everything>,
AllowDescendOrigin<Everything>,
);

/// A trader who believes all tokens are created equal to "weight" of any chain,
/// which is not true, but good enough to mock the fee payment of XCM execution.
Expand Down
Loading