Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asset-hubs: transfer assets via bridge using pallet-xcm #1224

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

140 changes: 140 additions & 0 deletions cumulus/parachains/common/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ use core::marker::PhantomData;
use frame_support::{
traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, ContainsPair},
weights::Weight,
DefaultNoBound,
};
use log;
use sp_runtime::traits::Get;
use xcm::latest::prelude::*;
use xcm_builder::ExporterFor;

/// A `ChargeFeeInFungibles` implementation that converts the output of
/// a given WeightToFee implementation an amount charged in
Expand Down Expand Up @@ -78,3 +80,141 @@ impl<Location: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation>
matches!(asset.id, Concrete(ref id) if id == origin && origin == &Location::get())
}
}

/// Trait for matching `Location`.
pub trait MatchesLocation<Location> {
fn matches(&self, location: &Location) -> bool;
}

/// Simple `MultiLocation` filter utility.
#[derive(Debug, DefaultNoBound)]
pub struct LocationFilter<Location> {
/// Requested location equals to `Location`.
pub equals_any: sp_std::vec::Vec<Location>,
/// Requested location starts with `Location`.
pub starts_with_any: sp_std::vec::Vec<Location>,
}

impl<Location> LocationFilter<Location> {
pub fn add_equals(mut self, filter: Location) -> Self {
self.equals_any.push(filter);
self
}
pub fn add_starts_with(mut self, filter: Location) -> Self {
self.starts_with_any.push(filter);
self
}
}

/// `MatchesLocation` implementation which works with `MultiLocation`.
impl MatchesLocation<MultiLocation> for LocationFilter<MultiLocation> {
fn matches(&self, location: &MultiLocation) -> bool {
for filter in &self.equals_any {
if location.eq(filter) {
return true
}
}
for filter in &self.starts_with_any {
if location.starts_with(filter) {
return true
}
}
false
}
}

/// `MatchesLocation` implementation which works with `InteriorMultiLocation`.
impl MatchesLocation<InteriorMultiLocation> for LocationFilter<InteriorMultiLocation> {
fn matches(&self, location: &InteriorMultiLocation) -> bool {
for filter in &self.equals_any {
if location.eq(filter) {
return true
}
}
for filter in &self.starts_with_any {
if location.starts_with(filter) {
return true
}
}
false
}
}

/// `FilteredNetworkExportTable` is adapter for `ExporterFor` implementation
/// which tries to find (`bridge_location`, `fees`) for requested `network` and `remote_location`.
///
/// Inspired by `xcm_builder::NetworkExportTable`:
/// the main difference is that `NetworkExportTable` does not check `remote_location`.
pub struct FilteredNetworkExportTable<T>(sp_std::marker::PhantomData<T>);
impl<
T: Get<
sp_std::vec::Vec<(
NetworkId,
LocationFilter<InteriorMultiLocation>,
MultiLocation,
Option<MultiAsset>,
)>,
>,
> ExporterFor for FilteredNetworkExportTable<T>
{
fn exporter_for(
network: &NetworkId,
remote_location: &InteriorMultiLocation,
_: &Xcm<()>,
) -> Option<(MultiLocation, Option<MultiAsset>)> {
T::get()
.into_iter()
.find(|(ref j, location_filter, ..)| {
j == network && location_filter.matches(remote_location)
})
.map(|(_, _, bridge_location, p)| (bridge_location, p))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn filtered_network_export_table_works() {
frame_support::parameter_types! {
pub BridgeLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1234)));

pub BridgeTable: sp_std::vec::Vec<(NetworkId, LocationFilter<InteriorMultiLocation>, MultiLocation, Option<MultiAsset>)> = sp_std::vec![
(
Kusama,
LocationFilter::default()
.add_equals(X1(Parachain(2000)))
.add_equals(X1(Parachain(3000)))
.add_equals(X1(Parachain(4000))),
BridgeLocation::get(),
None
)
];
}

let test_data = vec![
(Polkadot, X1(Parachain(1000)), None),
(Polkadot, X1(Parachain(2000)), None),
(Polkadot, X1(Parachain(3000)), None),
(Polkadot, X1(Parachain(4000)), None),
(Polkadot, X1(Parachain(5000)), None),
(Kusama, X1(Parachain(1000)), None),
(Kusama, X1(Parachain(2000)), Some((BridgeLocation::get(), None))),
(Kusama, X1(Parachain(3000)), Some((BridgeLocation::get(), None))),
(Kusama, X1(Parachain(4000)), Some((BridgeLocation::get(), None))),
(Kusama, X1(Parachain(5000)), None),
];

for (network, remote_location, expected_result) in test_data {
assert_eq!(
FilteredNetworkExportTable::<BridgeTable>::exporter_for(
&network,
&remote_location,
&Xcm::default()
),
expected_result,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,10 @@ impl_runtime_apis! {
}

fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> {
Err(BenchmarkError::Skip)
match xcm_config::bridging::BridgingBenchmarksHelper::prepare_universal_alias() {
Some(alias) => Ok(alias),
None => Err(BenchmarkError::Skip)
}
}

fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ impl<Call> XcmWeightInfo<Call> for AssetHubKusamaXcmWeight<Call> {
XcmGeneric::<Runtime>::clear_transact_status()
}
fn universal_origin(_: &Junction) -> Weight {
Weight::MAX
XcmGeneric::<Runtime>::universal_origin()
}
fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight {
Weight::MAX
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,16 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Minimum execution time: 2_886_000 picoseconds.
Weight::from_parts(3_015_000, 0)
}
// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
pub fn universal_origin() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `1489`
// Minimum execution time: 5_088_000 picoseconds.
Weight::from_parts(5_253_000, 1489)
.saturating_add(T::DbWeight::get().reads(1))
}
pub fn set_fees_mode() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
Expand Down
Loading