Skip to content

Commit b57f88b

Browse files
authored
NonReserve case support teleport (#786)
* none reserve add teleport * teleport multi_currency_adpater used for mock * rm log dep * clean comment * backport teleport to master
1 parent 244878e commit b57f88b

File tree

8 files changed

+586
-149
lines changed

8 files changed

+586
-149
lines changed

xtokens/src/lib.rs

+52-20
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#![allow(clippy::from_over_into)]
2222
#![allow(clippy::unused_unit)]
2323
#![allow(clippy::large_enum_variant)]
24+
#![allow(clippy::too_many_arguments)]
2425

2526
use frame_support::{
2627
log,
@@ -561,6 +562,9 @@ pub mod module {
561562
assets_to_fee_reserve.push(asset_to_fee_reserve.clone());
562563

563564
// First xcm sent to fee reserve chain and routed to dest chain.
565+
// We can use `MinXcmFee` configuration to decide which target parachain use
566+
// teleport. But as current there's only one case which is Parachain send back
567+
// asset to Statemine/t, So we set `use_teleport` to always `true` in this case.
564568
Self::execute_and_send_reserve_kind_xcm(
565569
origin_location.clone(),
566570
assets_to_fee_reserve,
@@ -569,6 +573,7 @@ pub mod module {
569573
&dest,
570574
Some(T::SelfLocation::get()),
571575
dest_weight,
576+
true,
572577
)?;
573578

574579
// Second xcm send to dest chain.
@@ -580,6 +585,7 @@ pub mod module {
580585
&dest,
581586
None,
582587
dest_weight,
588+
false,
583589
)?;
584590
} else {
585591
Self::execute_and_send_reserve_kind_xcm(
@@ -590,6 +596,7 @@ pub mod module {
590596
&dest,
591597
None,
592598
dest_weight,
599+
false,
593600
)?;
594601
}
595602

@@ -613,6 +620,7 @@ pub mod module {
613620
dest: &MultiLocation,
614621
maybe_recipient_override: Option<MultiLocation>,
615622
dest_weight: Weight,
623+
use_teleport: bool,
616624
) -> DispatchResult {
617625
let (transfer_kind, dest, reserve, recipient) = Self::transfer_kind(reserve, dest)?;
618626
let recipient = match maybe_recipient_override {
@@ -623,7 +631,9 @@ pub mod module {
623631
let mut msg = match transfer_kind {
624632
SelfReserveAsset => Self::transfer_self_reserve_asset(assets, fee, dest, recipient, dest_weight)?,
625633
ToReserve => Self::transfer_to_reserve(assets, fee, dest, recipient, dest_weight)?,
626-
ToNonReserve => Self::transfer_to_non_reserve(assets, fee, reserve, dest, recipient, dest_weight)?,
634+
ToNonReserve => {
635+
Self::transfer_to_non_reserve(assets, fee, reserve, dest, recipient, dest_weight, use_teleport)?
636+
}
627637
};
628638

629639
let weight = T::Weigher::weight(&mut msg).map_err(|()| Error::<T>::UnweighableMessage)?;
@@ -681,6 +691,7 @@ pub mod module {
681691
dest: MultiLocation,
682692
recipient: MultiLocation,
683693
dest_weight: Weight,
694+
use_teleport: bool,
684695
) -> Result<Xcm<T::Call>, DispatchError> {
685696
let mut reanchored_dest = dest.clone();
686697
if reserve == MultiLocation::parent() {
@@ -695,25 +706,46 @@ pub mod module {
695706
}
696707
}
697708

698-
Ok(Xcm(vec![
699-
WithdrawAsset(assets.clone()),
700-
InitiateReserveWithdraw {
701-
assets: All.into(),
702-
reserve: reserve.clone(),
703-
xcm: Xcm(vec![
704-
Self::buy_execution(half(&fee), &reserve, dest_weight)?,
705-
DepositReserveAsset {
706-
assets: All.into(),
707-
max_assets: assets.len() as u32,
708-
dest: reanchored_dest,
709-
xcm: Xcm(vec![
710-
Self::buy_execution(half(&fee), &dest, dest_weight)?,
711-
Self::deposit_asset(recipient, assets.len() as u32),
712-
]),
713-
},
714-
]),
715-
},
716-
]))
709+
if !use_teleport {
710+
Ok(Xcm(vec![
711+
WithdrawAsset(assets.clone()),
712+
InitiateReserveWithdraw {
713+
assets: All.into(),
714+
reserve: reserve.clone(),
715+
xcm: Xcm(vec![
716+
Self::buy_execution(half(&fee), &reserve, dest_weight)?,
717+
DepositReserveAsset {
718+
assets: All.into(),
719+
max_assets: assets.len() as u32,
720+
dest: reanchored_dest,
721+
xcm: Xcm(vec![
722+
Self::buy_execution(half(&fee), &dest, dest_weight)?,
723+
Self::deposit_asset(recipient, assets.len() as u32),
724+
]),
725+
},
726+
]),
727+
},
728+
]))
729+
} else {
730+
Ok(Xcm(vec![
731+
WithdrawAsset(assets.clone()),
732+
InitiateReserveWithdraw {
733+
assets: All.into(),
734+
reserve: reserve.clone(),
735+
xcm: Xcm(vec![
736+
Self::buy_execution(half(&fee), &reserve, dest_weight)?,
737+
InitiateTeleport {
738+
assets: All.into(),
739+
dest: reanchored_dest,
740+
xcm: Xcm(vec![
741+
Self::buy_execution(half(&fee), &dest, dest_weight)?,
742+
Self::deposit_asset(recipient, assets.len() as u32),
743+
]),
744+
},
745+
]),
746+
},
747+
]))
748+
}
717749
}
718750

719751
fn deposit_asset(recipient: MultiLocation, max_assets: u32) -> Instruction<()> {

xtokens/src/mock/mod.rs

+83-4
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ use scale_info::TypeInfo;
77
use serde::{Deserialize, Serialize};
88
use sp_io::TestExternalities;
99
use sp_runtime::AccountId32;
10+
use xcm_executor::traits::WeightTrader;
11+
use xcm_executor::Assets;
1012

1113
use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain};
1214

1315
pub mod para;
1416
pub mod para_relative_view;
17+
pub mod para_teleport;
1518
pub mod relay;
19+
pub mod teleport_currency_adapter;
1620

1721
pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]);
1822
pub const BOB: AccountId32 = AccountId32::new([1u8; 32]);
@@ -32,6 +36,8 @@ pub enum CurrencyId {
3236
B1,
3337
/// Parachain B B2 token
3438
B2,
39+
/// Parachain C token
40+
C,
3541
/// Parachain D token
3642
D,
3743
}
@@ -46,6 +52,7 @@ impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
4652
CurrencyId::B => Some((Parent, Parachain(2), GeneralKey("B".into())).into()),
4753
CurrencyId::B1 => Some((Parent, Parachain(2), GeneralKey("B1".into())).into()),
4854
CurrencyId::B2 => Some((Parent, Parachain(2), GeneralKey("B2".into())).into()),
55+
CurrencyId::C => Some((Parent, Parachain(3), GeneralKey("C".into())).into()),
4956
CurrencyId::D => Some((Parent, Parachain(4), GeneralKey("D".into())).into()),
5057
}
5158
}
@@ -57,6 +64,7 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
5764
let b: Vec<u8> = "B".into();
5865
let b1: Vec<u8> = "B1".into();
5966
let b2: Vec<u8> = "B2".into();
67+
let c: Vec<u8> = "C".into();
6068
let d: Vec<u8> = "D".into();
6169
if l == MultiLocation::parent() {
6270
return Some(CurrencyId::R);
@@ -68,6 +76,7 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
6876
X2(Parachain(2), GeneralKey(k)) if k == b => Some(CurrencyId::B),
6977
X2(Parachain(2), GeneralKey(k)) if k == b1 => Some(CurrencyId::B1),
7078
X2(Parachain(2), GeneralKey(k)) if k == b2 => Some(CurrencyId::B2),
79+
X2(Parachain(3), GeneralKey(k)) if k == c => Some(CurrencyId::C),
7180
X2(Parachain(4), GeneralKey(k)) if k == d => Some(CurrencyId::D),
7281
_ => None,
7382
},
@@ -77,6 +86,7 @@ impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
7786
X1(GeneralKey(k)) if k == a1 => Some(CurrencyId::A1),
7887
X1(GeneralKey(k)) if k == b1 => Some(CurrencyId::B1),
7988
X1(GeneralKey(k)) if k == b2 => Some(CurrencyId::B2),
89+
X1(GeneralKey(k)) if k == c => Some(CurrencyId::C),
8090
X1(GeneralKey(k)) if k == d => Some(CurrencyId::D),
8191
_ => None,
8292
},
@@ -121,10 +131,10 @@ decl_test_parachain! {
121131

122132
decl_test_parachain! {
123133
pub struct ParaC {
124-
Runtime = para::Runtime,
125-
XcmpMessageHandler = para::XcmpQueue,
126-
DmpMessageHandler = para::DmpQueue,
127-
new_ext = para_ext(3),
134+
Runtime = para_teleport::Runtime,
135+
XcmpMessageHandler = para_teleport::XcmpQueue,
136+
DmpMessageHandler = para_teleport::DmpQueue,
137+
new_ext = para_teleport_ext(3),
128138
}
129139
}
130140

@@ -166,6 +176,8 @@ pub type ParaXTokens = orml_xtokens::Pallet<para::Runtime>;
166176
pub type ParaRelativeTokens = orml_tokens::Pallet<para_relative_view::Runtime>;
167177
pub type ParaRelativeXTokens = orml_xtokens::Pallet<para_relative_view::Runtime>;
168178

179+
pub type ParaTeleportTokens = orml_tokens::Pallet<para_teleport::Runtime>;
180+
169181
pub fn para_ext(para_id: u32) -> TestExternalities {
170182
use para::{Runtime, System};
171183

@@ -190,6 +202,30 @@ pub fn para_ext(para_id: u32) -> TestExternalities {
190202
ext
191203
}
192204

205+
pub fn para_teleport_ext(para_id: u32) -> TestExternalities {
206+
use para_teleport::{Runtime, System};
207+
208+
let mut t = frame_system::GenesisConfig::default()
209+
.build_storage::<Runtime>()
210+
.unwrap();
211+
212+
let parachain_info_config = parachain_info::GenesisConfig {
213+
parachain_id: para_id.into(),
214+
};
215+
<parachain_info::GenesisConfig as GenesisBuild<Runtime, _>>::assimilate_storage(&parachain_info_config, &mut t)
216+
.unwrap();
217+
218+
orml_tokens::GenesisConfig::<Runtime> {
219+
balances: vec![(ALICE, CurrencyId::R, 1_000)],
220+
}
221+
.assimilate_storage(&mut t)
222+
.unwrap();
223+
224+
let mut ext = TestExternalities::new(t);
225+
ext.execute_with(|| System::set_block_number(1));
226+
ext
227+
}
228+
193229
pub fn relay_ext() -> sp_io::TestExternalities {
194230
use relay::{Runtime, System};
195231

@@ -207,3 +243,46 @@ pub fn relay_ext() -> sp_io::TestExternalities {
207243
ext.execute_with(|| System::set_block_number(1));
208244
ext
209245
}
246+
247+
/// A trader who believes all tokens are created equal to "weight" of any chain,
248+
/// which is not true, but good enough to mock the fee payment of XCM execution.
249+
///
250+
/// This mock will always trade `n` amount of weight to `n` amount of tokens.
251+
pub struct AllTokensAreCreatedEqualToWeight(MultiLocation);
252+
impl WeightTrader for AllTokensAreCreatedEqualToWeight {
253+
fn new() -> Self {
254+
Self(MultiLocation::parent())
255+
}
256+
257+
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
258+
let asset_id = payment
259+
.fungible
260+
.iter()
261+
.next()
262+
.expect("Payment must be something; qed")
263+
.0;
264+
let required = MultiAsset {
265+
id: asset_id.clone(),
266+
fun: Fungible(weight as u128),
267+
};
268+
269+
if let MultiAsset {
270+
fun: _,
271+
id: Concrete(ref id),
272+
} = &required
273+
{
274+
self.0 = id.clone();
275+
}
276+
277+
let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?;
278+
Ok(unused)
279+
}
280+
281+
fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
282+
if weight.is_zero() {
283+
None
284+
} else {
285+
Some((self.0.clone(), weight as u128).into())
286+
}
287+
}
288+
}

xtokens/src/mock/para.rs

+6-48
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use frame_system::EnsureRoot;
1010
use sp_core::H256;
1111
use sp_runtime::{
1212
testing::Header,
13-
traits::{Convert, IdentityLookup, Zero},
13+
traits::{Convert, IdentityLookup},
1414
AccountId32,
1515
};
1616

@@ -20,11 +20,12 @@ use polkadot_parachain::primitives::Sibling;
2020
use xcm::latest::prelude::*;
2121
use xcm_builder::{
2222
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, LocationInverter,
23-
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
23+
NativeAsset, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
2424
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
2525
};
26-
use xcm_executor::{traits::WeightTrader, Assets, Config, XcmExecutor};
26+
use xcm_executor::{Config, XcmExecutor};
2727

28+
use crate::mock::AllTokensAreCreatedEqualToWeight;
2829
use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key};
2930
use orml_xcm_support::{IsNativeConcrete, MultiCurrencyAdapter, MultiNativeAsset};
3031

@@ -133,57 +134,14 @@ pub type LocalAssetTransactor = MultiCurrencyAdapter<
133134
pub type XcmRouter = ParachainXcmRouter<ParachainInfo>;
134135
pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom<Everything>);
135136

136-
/// A trader who believes all tokens are created equal to "weight" of any chain,
137-
/// which is not true, but good enough to mock the fee payment of XCM execution.
138-
///
139-
/// This mock will always trade `n` amount of weight to `n` amount of tokens.
140-
pub struct AllTokensAreCreatedEqualToWeight(MultiLocation);
141-
impl WeightTrader for AllTokensAreCreatedEqualToWeight {
142-
fn new() -> Self {
143-
Self(MultiLocation::parent())
144-
}
145-
146-
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
147-
let asset_id = payment
148-
.fungible
149-
.iter()
150-
.next()
151-
.expect("Payment must be something; qed")
152-
.0;
153-
let required = MultiAsset {
154-
id: asset_id.clone(),
155-
fun: Fungible(weight as u128),
156-
};
157-
158-
if let MultiAsset {
159-
fun: _,
160-
id: Concrete(ref id),
161-
} = &required
162-
{
163-
self.0 = id.clone();
164-
}
165-
166-
let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?;
167-
Ok(unused)
168-
}
169-
170-
fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
171-
if weight.is_zero() {
172-
None
173-
} else {
174-
Some((self.0.clone(), weight as u128).into())
175-
}
176-
}
177-
}
178-
179137
pub struct XcmConfig;
180138
impl Config for XcmConfig {
181139
type Call = Call;
182140
type XcmSender = XcmRouter;
183141
type AssetTransactor = LocalAssetTransactor;
184142
type OriginConverter = XcmOriginToCallOrigin;
185143
type IsReserve = MultiNativeAsset<AbsoluteReserveProvider>;
186-
type IsTeleporter = ();
144+
type IsTeleporter = NativeAsset;
187145
type LocationInverter = LocationInverter<Ancestry>;
188146
type Barrier = Barrier;
189147
type Weigher = FixedWeightBounds<ConstU64<10>, Call, ConstU32<100>>;
@@ -277,7 +235,7 @@ parameter_type_with_key! {
277235
pub ParachainMinFee: |location: MultiLocation| -> Option<u128> {
278236
#[allow(clippy::match_ref_pats)] // false positive
279237
match (location.parents, location.first_interior()) {
280-
(1, Some(Parachain(2))) => Some(40),
238+
(1, Some(Parachain(3))) => Some(40),
281239
_ => None,
282240
}
283241
};

0 commit comments

Comments
 (0)