Skip to content

Commit 3a77e1a

Browse files
authored
Cross-chain transfer rework (#432)
* Reserve chain trait. * Rework cross-chain transfer. * Remove relay chain balance convert. * Add 'Parse' trait. * Change transfer_multiasset fn signature. * Add transfer dispatchable call. * Update doc. * Use xcm-simulator to mock network. * Send relay chain asset to sibling unit test. * Move location traits into orml-traits. * Add MultiNativeAsset filter for is reserve check. * More unit tests. * Failing edge case unit tests. * Handle zero amount asset case. * Fix mocks. * Renaming.
1 parent ea01954 commit 3a77e1a

File tree

9 files changed

+1043
-187
lines changed

9 files changed

+1043
-187
lines changed

traits/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ num-traits = { version = "0.2.14", default-features = false }
1717
impl-trait-for-tuples = "0.2.1"
1818
frame-support = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false }
1919
orml-utilities = { path = "../utilities", version = "0.4.1-dev", default-features = false }
20+
xcm = { git = "https://github.com/paritytech/polkadot", branch = "rococo-v1", default-features = false }
2021

2122
funty = { version = "=1.1.0", default-features = false } # https://github.com/bitvecto-rs/bitvec/issues/105
2223

@@ -31,4 +32,5 @@ std = [
3132
"num-traits/std",
3233
"frame-support/std",
3334
"orml-utilities/std",
35+
"xcm/std",
3436
]

traits/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub mod auction;
2828
pub mod currency;
2929
pub mod data_provider;
3030
pub mod get_by_key;
31+
pub mod location;
3132
pub mod nft;
3233
pub mod price;
3334
pub mod rewards;

traits/src/location.rs

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use xcm::v0::{
2+
Junction::{self, *},
3+
MultiAsset, MultiLocation,
4+
};
5+
6+
pub trait Parse {
7+
/// Returns the "chain" location part. It could be parent, sibling
8+
/// parachain, or child parachain.
9+
fn chain_part(&self) -> Option<MultiLocation>;
10+
/// Returns "non-chain" location part.
11+
fn non_chain_part(&self) -> Option<MultiLocation>;
12+
}
13+
14+
fn is_chain_junction(junction: Option<&Junction>) -> bool {
15+
matches!(junction, Some(Parent) | Some(Parachain { id: _ }))
16+
}
17+
18+
impl Parse for MultiLocation {
19+
fn chain_part(&self) -> Option<MultiLocation> {
20+
match (self.first(), self.at(1)) {
21+
(Some(Parent), Some(Parachain { id })) => Some((Parent, Parachain { id: *id }).into()),
22+
(Some(Parent), _) => Some(Parent.into()),
23+
(Some(Parachain { id }), _) => Some(Parachain { id: *id }.into()),
24+
_ => None,
25+
}
26+
}
27+
28+
fn non_chain_part(&self) -> Option<MultiLocation> {
29+
let mut location = self.clone();
30+
while is_chain_junction(location.first()) {
31+
let _ = location.take_first();
32+
}
33+
34+
if location != MultiLocation::Null {
35+
Some(location)
36+
} else {
37+
None
38+
}
39+
}
40+
}
41+
42+
pub trait Reserve {
43+
/// Returns assets reserve location.
44+
fn reserve(&self) -> Option<MultiLocation>;
45+
}
46+
47+
impl Reserve for MultiAsset {
48+
fn reserve(&self) -> Option<MultiLocation> {
49+
if let MultiAsset::ConcreteFungible { id, .. } = self {
50+
id.chain_part()
51+
} else {
52+
None
53+
}
54+
}
55+
}
56+
57+
#[cfg(test)]
58+
mod tests {
59+
use super::*;
60+
61+
const PARACHAIN: Junction = Parachain { id: 1 };
62+
const GENERAL_INDEX: Junction = GeneralIndex { id: 1 };
63+
64+
fn concrete_fungible(id: MultiLocation) -> MultiAsset {
65+
MultiAsset::ConcreteFungible { id, amount: 1 }
66+
}
67+
68+
#[test]
69+
fn parent_as_reserve_chain() {
70+
assert_eq!(
71+
concrete_fungible(MultiLocation::X2(Parent, GENERAL_INDEX)).reserve(),
72+
Some(Parent.into())
73+
);
74+
}
75+
76+
#[test]
77+
fn sibling_parachain_as_reserve_chain() {
78+
assert_eq!(
79+
concrete_fungible(MultiLocation::X3(Parent, PARACHAIN, GENERAL_INDEX)).reserve(),
80+
Some((Parent, PARACHAIN).into())
81+
);
82+
}
83+
84+
#[test]
85+
fn child_parachain_as_reserve_chain() {
86+
assert_eq!(
87+
concrete_fungible(MultiLocation::X2(PARACHAIN, GENERAL_INDEX)).reserve(),
88+
Some(PARACHAIN.into())
89+
);
90+
}
91+
92+
#[test]
93+
fn no_reserve_chain() {
94+
assert_eq!(
95+
concrete_fungible(MultiLocation::X1(GeneralKey("DOT".into()))).reserve(),
96+
None
97+
);
98+
}
99+
100+
#[test]
101+
fn non_chain_part_works() {
102+
assert_eq!(MultiLocation::X1(Parent).non_chain_part(), None);
103+
assert_eq!(MultiLocation::X2(Parent, PARACHAIN).non_chain_part(), None);
104+
assert_eq!(MultiLocation::X1(PARACHAIN).non_chain_part(), None);
105+
106+
assert_eq!(
107+
MultiLocation::X2(Parent, GENERAL_INDEX).non_chain_part(),
108+
Some(GENERAL_INDEX.into())
109+
);
110+
assert_eq!(
111+
MultiLocation::X3(Parent, GENERAL_INDEX, GENERAL_INDEX).non_chain_part(),
112+
Some((GENERAL_INDEX, GENERAL_INDEX).into())
113+
);
114+
assert_eq!(
115+
MultiLocation::X3(Parent, PARACHAIN, GENERAL_INDEX).non_chain_part(),
116+
Some(GENERAL_INDEX.into())
117+
);
118+
assert_eq!(
119+
MultiLocation::X2(PARACHAIN, GENERAL_INDEX).non_chain_part(),
120+
Some(GENERAL_INDEX.into())
121+
);
122+
}
123+
}

unknown-tokens/src/tests.rs

-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
use super::*;
66
use mock::{Event, *};
77

8-
use codec::{Decode, Encode};
9-
108
use frame_support::{assert_err, assert_ok};
119
use xcm::v0::Junction;
1210

xcm-support/src/lib.rs

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use sp_std::{
2424
use xcm::v0::{Junction, MultiAsset, MultiLocation, Xcm};
2525
use xcm_executor::traits::{FilterAssetLocation, MatchesFungible, NativeAsset};
2626

27+
use orml_traits::location::Reserve;
28+
2729
pub use currency_adapter::MultiCurrencyAdapter;
2830

2931
mod currency_adapter;
@@ -90,6 +92,20 @@ impl<Pairs: Get<BTreeSet<(Vec<u8>, MultiLocation)>>> FilterAssetLocation for Nat
9092
}
9193
}
9294

95+
/// A `FilterAssetLocation` implementation. Filters multi native assets whose
96+
/// reserve is same with `origin`.
97+
pub struct MultiNativeAsset;
98+
impl FilterAssetLocation for MultiNativeAsset {
99+
fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {
100+
if let Some(ref reserve) = asset.reserve() {
101+
if reserve == origin {
102+
return true;
103+
}
104+
}
105+
false
106+
}
107+
}
108+
93109
/// `CurrencyIdConversion` implementation. Converts relay chain tokens, or
94110
/// parachain tokens that could be decoded from a general key.
95111
pub struct CurrencyIdConverter<CurrencyId, RelayChainCurrencyId>(

xtokens/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,21 @@ cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branc
2222
xcm = { git = "https://github.com/paritytech/polkadot", branch = "rococo-v1", default-features = false }
2323

2424
orml-xcm-support = { path = "../xcm-support", default-features = false }
25+
orml-traits = { path = "../traits", default-features = false}
2526

2627
[dev-dependencies]
2728
sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" }
2829
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", branch = "rococo-v1" }
30+
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "rococo-v1" }
31+
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" }
32+
xcm-simulator = { git = "https://github.com/shaunxw/xcm-simulator", branch = "master" }
33+
cumulus-pallet-xcm-handler = { git = "https://github.com/paritytech/cumulus", branch = "rococo-v1" }
34+
parachain-info = { git = "https://github.com/paritytech/cumulus", branch = "rococo-v1" }
35+
xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "rococo-v1" }
36+
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "rococo-v1" }
37+
2938
orml-tokens = { path = "../tokens", version = "0.4.1-dev" }
39+
orml-traits = { path = "../traits", version = "0.4.1-dev" }
3040

3141
[features]
3242
default = ["std"]
@@ -41,4 +51,5 @@ std = [
4151
"cumulus-primitives-core/std",
4252
"xcm/std",
4353
"orml-xcm-support/std",
54+
"orml-traits/std",
4455
]

0 commit comments

Comments
 (0)