Skip to content

Commit 6856a5c

Browse files
authored
Add orml-xcm module. (#539)
* Add Xcm module. * Remove unused deps. * Make clippy happy. * Add unit tests for orml-xcm.
1 parent 3bf16d6 commit 6856a5c

File tree

6 files changed

+188
-2
lines changed

6 files changed

+188
-2
lines changed

Cargo.dev.toml

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ members = [
1717
"vesting",
1818
"rewards",
1919
"nft",
20+
"xcm",
2021
"xtokens",
2122
"xcm-support",
2223
"unknown-tokens",
@@ -92,6 +93,7 @@ parachain-info = { git = "https://github.com/paritytech//cumulus", rev = "c5c3ab
9293
xcm = { git = "https://github.com/paritytech//polkadot", rev = "5d35bac7408a4cb12a578764217d06f3920b36aa" }
9394
xcm-executor = { git = "https://github.com/paritytech//polkadot", rev = "5d35bac7408a4cb12a578764217d06f3920b36aa" }
9495
xcm-builder = { git = "https://github.com/paritytech//polkadot", rev = "5d35bac7408a4cb12a578764217d06f3920b36aa" }
96+
pallet-xcm = { git = "https://github.com/paritytech//polkadot", rev = "5d35bac7408a4cb12a578764217d06f3920b36aa" }
9597
polkadot-core-primitives = { git = "https://github.com/paritytech//polkadot", rev = "5d35bac7408a4cb12a578764217d06f3920b36aa" }
9698
polkadot-runtime-parachains = { git = "https://github.com/paritytech//polkadot", rev = "5d35bac7408a4cb12a578764217d06f3920b36aa" }
9799
polkadot-parachain = { git = "https://github.com/paritytech//polkadot", rev = "5d35bac7408a4cb12a578764217d06f3920b36aa" }

xcm/Cargo.toml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
name = "orml-xcm"
3+
description = "XCM message helpers."
4+
repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/xcm"
5+
license = "Apache-2.0"
6+
version = "0.4.1-dev"
7+
authors = ["Acala Developers"]
8+
edition = "2018"
9+
10+
[dependencies]
11+
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
12+
13+
frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.7", default-features = false }
14+
frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.7", default-features = false }
15+
16+
xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.7", default-features = false }
17+
pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.7", default-features = false }
18+
19+
[features]
20+
default = ["std"]
21+
std = [
22+
"codec/std",
23+
"frame-support/std",
24+
"frame-system/std",
25+
"xcm/std",
26+
"pallet-xcm/std",
27+
]
28+
try-runtime = ["frame-support/try-runtime"]

xcm/src/lib.rs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//! # Xcm Module
2+
3+
#![cfg_attr(not(feature = "std"), no_std)]
4+
#![allow(clippy::large_enum_variant)]
5+
6+
use frame_support::{pallet_prelude::*, traits::EnsureOrigin};
7+
use frame_system::pallet_prelude::*;
8+
9+
use xcm::v0::prelude::*;
10+
11+
pub use module::*;
12+
13+
#[frame_support::pallet]
14+
pub mod module {
15+
use super::*;
16+
17+
#[pallet::config]
18+
pub trait Config: frame_system::Config + pallet_xcm::Config {
19+
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
20+
21+
/// The required origin for sending XCM as parachain sovereign.
22+
///
23+
/// Typically root or the majority of collective.
24+
type SovereignOrigin: EnsureOrigin<Self::Origin>;
25+
}
26+
27+
#[pallet::pallet]
28+
pub struct Pallet<T>(_);
29+
30+
#[pallet::event]
31+
#[pallet::generate_deposit(pub(super) fn deposit_event)]
32+
pub enum Event<T: Config> {
33+
/// XCM message sent. \[from, to, message\]
34+
Sent(MultiLocation, MultiLocation, Xcm<()>),
35+
}
36+
37+
#[pallet::error]
38+
pub enum Error<T> {
39+
/// The message and destination combination was not recognized as being
40+
/// reachable.
41+
Unreachable,
42+
/// The message and destination was recognized as being reachable but
43+
/// the operation could not be completed.
44+
SendFailure,
45+
}
46+
47+
#[pallet::call]
48+
impl<T: Config> Pallet<T> {
49+
/// Send an XCM message as parachain sovereign.
50+
#[pallet::weight(100_000_000)]
51+
pub fn send_as_sovereign(origin: OriginFor<T>, dest: MultiLocation, message: Xcm<()>) -> DispatchResult {
52+
let _ = T::SovereignOrigin::ensure_origin(origin)?;
53+
pallet_xcm::Pallet::<T>::send_xcm(MultiLocation::Null, dest.clone(), message.clone()).map_err(
54+
|e| match e {
55+
XcmError::CannotReachDestination(..) => Error::<T>::Unreachable,
56+
_ => Error::<T>::SendFailure,
57+
},
58+
)?;
59+
Self::deposit_event(Event::Sent(MultiLocation::Null, dest, message));
60+
Ok(())
61+
}
62+
}
63+
}

xtokens/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "release
4545
polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.7" }
4646

4747
orml-tokens = { path = "../tokens" }
48+
orml-xcm = { path = "../xcm" }
4849
xcm-simulator = { git = "https://github.com/shaunxw/xcm-simulator.git", branch = "polkadot-v0.9.7"}
4950

5051
[features]

xtokens/src/mock/para.rs

+6
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ impl orml_xtokens::Config for Runtime {
231231
type BaseXcmWeight = BaseXcmWeight;
232232
}
233233

234+
impl orml_xcm::Config for Runtime {
235+
type Event = Event;
236+
type SovereignOrigin = EnsureRoot<AccountId>;
237+
}
238+
234239
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
235240
type Block = frame_system::mocking::MockBlock<Runtime>;
236241

@@ -252,5 +257,6 @@ construct_runtime!(
252257
XTokens: orml_xtokens::{Pallet, Storage, Call, Event<T>},
253258

254259
PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin},
260+
OrmlXcm: orml_xcm::{Pallet, Call, Event<T>},
255261
}
256262
);

xtokens/src/tests.rs

+88-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#![cfg(test)]
22

33
use super::*;
4+
use codec::Encode;
45
use cumulus_primitives_core::ParaId;
5-
use frame_support::{assert_noop, assert_ok, traits::Currency};
6+
use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency};
67
use mock::*;
78
use orml_traits::MultiCurrency;
89
// use polkadot_parachain::primitives::{AccountIdConversion, Sibling};
910
use polkadot_parachain::primitives::AccountIdConversion;
1011
use sp_runtime::AccountId32;
11-
use xcm::v0::{Junction, NetworkId};
12+
use xcm::v0::{Junction, NetworkId, Order};
1213
use xcm_simulator::TestExt;
1314

1415
fn para_a_account() -> AccountId32 {
@@ -325,3 +326,88 @@ fn transfer_to_invalid_dest_fails() {
325326
);
326327
});
327328
}
329+
330+
#[test]
331+
fn send_as_sovereign() {
332+
TestNet::reset();
333+
334+
Relay::execute_with(|| {
335+
let _ = RelayBalances::deposit_creating(&para_a_account(), 1_000_000_000_000);
336+
});
337+
338+
ParaA::execute_with(|| {
339+
use xcm::v0::OriginKind::SovereignAccount;
340+
341+
let call = relay::Call::System(frame_system::Call::<relay::Runtime>::remark_with_event(vec![1, 1, 1]));
342+
assert_ok!(para::OrmlXcm::send_as_sovereign(
343+
para::Origin::root(),
344+
Junction::Parent.into(),
345+
WithdrawAsset {
346+
assets: vec![MultiAsset::ConcreteFungible {
347+
id: MultiLocation::Null,
348+
amount: 1_000_000_000_000
349+
}],
350+
effects: vec![Order::BuyExecution {
351+
fees: MultiAsset::All,
352+
weight: 10_000_000,
353+
debt: 10_000_000,
354+
halt_on_error: true,
355+
xcm: vec![Transact {
356+
origin_type: SovereignAccount,
357+
require_weight_at_most: 1_000_000_000,
358+
call: call.encode().into(),
359+
}],
360+
}]
361+
}
362+
));
363+
});
364+
365+
Relay::execute_with(|| {
366+
relay::System::events().iter().any(|r| {
367+
if let relay::Event::System(frame_system::Event::<relay::Runtime>::Remarked(_, _)) = r.event {
368+
true
369+
} else {
370+
false
371+
}
372+
});
373+
})
374+
}
375+
376+
#[test]
377+
fn send_as_sovereign_fails_if_bad_origin() {
378+
TestNet::reset();
379+
380+
Relay::execute_with(|| {
381+
let _ = RelayBalances::deposit_creating(&para_a_account(), 1_000_000_000_000);
382+
});
383+
384+
ParaA::execute_with(|| {
385+
use xcm::v0::OriginKind::SovereignAccount;
386+
387+
let call = relay::Call::System(frame_system::Call::<relay::Runtime>::remark_with_event(vec![1, 1, 1]));
388+
assert_err!(
389+
para::OrmlXcm::send_as_sovereign(
390+
para::Origin::signed(ALICE),
391+
Junction::Parent.into(),
392+
WithdrawAsset {
393+
assets: vec![MultiAsset::ConcreteFungible {
394+
id: MultiLocation::Null,
395+
amount: 1_000_000_000_000
396+
}],
397+
effects: vec![Order::BuyExecution {
398+
fees: MultiAsset::All,
399+
weight: 10_000_000,
400+
debt: 10_000_000,
401+
halt_on_error: true,
402+
xcm: vec![Transact {
403+
origin_type: SovereignAccount,
404+
require_weight_at_most: 1_000_000_000,
405+
call: call.encode().into(),
406+
}],
407+
}]
408+
}
409+
),
410+
DispatchError::BadOrigin,
411+
);
412+
});
413+
}

0 commit comments

Comments
 (0)