Skip to content

Commit

Permalink
Allow xcm-transacts from all chains (#1055)
Browse files Browse the repository at this point in the history
* Allow xcm-trasnacts from all chains

Signed-off-by: Georgi Zlatarev <georgi.zlatarev@manta.network>

* Add xcm-transact to Dolphin and Manta

Signed-off-by: Georgi Zlatarev <georgi.zlatarev@manta.network>

* Comments

Signed-off-by: Georgi Zlatarev <georgi.zlatarev@manta.network>

* Add test

Signed-off-by: Georgi Zlatarev <georgi.zlatarev@manta.network>

* Fix clippy

Signed-off-by: Georgi Zlatarev <georgi.zlatarev@manta.network>

* Add missing AllowTopLevelPaidExecutionFrom

Signed-off-by: Georgi Zlatarev <georgi.zlatarev@manta.network>

---------

Signed-off-by: Georgi Zlatarev <georgi.zlatarev@manta.network>
  • Loading branch information
ghzlatarev authored Jul 12, 2023
1 parent 9b85510 commit 5c37a5d
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 11 deletions.
61 changes: 58 additions & 3 deletions primitives/manta/src/xcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ use sp_std::marker::PhantomData;

use crate::assets::{AssetIdLocationMap, UnitsPerSecond};
use frame_support::{
ensure,
pallet_prelude::Get,
traits::{fungibles::Mutate, tokens::ExistenceRequirement},
traits::{fungibles::Mutate, tokens::ExistenceRequirement, Contains},
};
use frame_system::Config;
use xcm::{
latest::{prelude::Concrete, Error as XcmError},
latest::{
prelude::{BuyExecution, Concrete, DescendOrigin, WithdrawAsset},
Error as XcmError,
WeightLimit::{Limited, Unlimited},
Xcm,
},
v1::{
AssetId as XcmAssetId, Fungibility,
Junction::{AccountId32, Parachain},
Expand All @@ -43,7 +49,7 @@ use xcm_builder::TakeRevenue;
use xcm_executor::{
traits::{
Convert as XcmConvert, FilterAssetLocation, MatchesFungible, MatchesFungibles,
TransactAsset, WeightTrader,
ShouldExecute, TransactAsset, WeightTrader,
},
Assets,
};
Expand Down Expand Up @@ -410,3 +416,52 @@ where
Ok(asset.clone().into())
}
}

/// Barrier allowing a top level paid message with DescendOrigin instruction first
pub struct AllowTopLevelPaidExecutionDescendOriginFirst<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionDescendOriginFirst<T> {
fn should_execute<Call>(
origin: &MultiLocation,
message: &mut Xcm<Call>,
max_weight: u64,
_weight_credit: &mut u64,
) -> Result<(), ()> {
log::trace!(
target: "xcm::barriers",
"AllowTopLevelPaidExecutionDescendOriginFirst origin:
{:?}, message: {:?}, max_weight: {:?}, weight_credit: {:?}",
origin, message, max_weight, _weight_credit,
);
ensure!(T::contains(origin), ());
let mut iter = message.0.iter_mut();
// Make sure the first instruction is DescendOrigin
iter.next()
.filter(|instruction| matches!(instruction, DescendOrigin(_)))
.ok_or(())?;

// Then WithdrawAsset
iter.next()
.filter(|instruction| matches!(instruction, WithdrawAsset(_)))
.ok_or(())?;

// Then BuyExecution
let 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(()),
}
}
}
11 changes: 8 additions & 3 deletions runtime/calamari/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use manta_primitives::{
assets::AssetIdLocationConvert,
types::{AccountId, Balance, CalamariAssetId},
xcm::{
AccountIdToMultiLocation, FirstAssetTrader, IsNativeConcrete, MultiAssetAdapter,
MultiNativeAsset,
AccountIdToMultiLocation, AllowTopLevelPaidExecutionDescendOriginFirst, FirstAssetTrader,
IsNativeConcrete, MultiAssetAdapter, MultiNativeAsset,
},
};
use orml_traits::location::AbsoluteReserveProvider;
Expand All @@ -44,7 +44,7 @@ use sp_runtime::traits::Convert;
use sp_std::prelude::*;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ConvertedConcreteAssetId,
EnsureXcmOrigin, FixedRateOfFungible, LocationInverter, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
Expand Down Expand Up @@ -93,6 +93,8 @@ pub type LocationToAccountId = (
SiblingParachainConvertsVia<Sibling, AccountId>,
// Straight up local `AccountId32` origins just alias directly to `AccountId`.
AccountId32Aliases<RelayNetwork, AccountId>,
// Converts multilocation into a 32 byte hash for local `AccountId`s
Account32Hash<RelayNetwork, AccountId>,
);

/// This is the type to convert an (incoming) XCM origin into a local `Origin` instance,
Expand Down Expand Up @@ -164,6 +166,9 @@ match_types! {
pub type Barrier = (
// Allows local origin messages which call weight_credit >= weight_limit.
TakeWeightCredit,
// Allows execution of Transact XCM instruction from configurable set of origins
// as long as the message is in the format DescendOrigin + WithdrawAsset + BuyExecution
AllowTopLevelPaidExecutionDescendOriginFirst<Everything>,
// Allows non-local origin messages, for example from from the xcmp queue,
// which have the ability to deposit assets and pay for their own execution.
AllowTopLevelPaidExecutionFrom<Everything>,
Expand Down
12 changes: 10 additions & 2 deletions runtime/integration-tests/src/xcm_mock/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ use manta_primitives::{
},
constants::{ASSET_MANAGER_PALLET_ID, CALAMARI_DECIMAL, WEIGHT_PER_SECOND},
types::{BlockNumber, CalamariAssetId, Header},
xcm::{FirstAssetTrader, IsNativeConcrete, MultiAssetAdapter, MultiNativeAsset},
xcm::{
AllowTopLevelPaidExecutionDescendOriginFirst, FirstAssetTrader, IsNativeConcrete,
MultiAssetAdapter, MultiNativeAsset,
},
};
use pallet_xcm::XcmPassthrough;
use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
Expand All @@ -53,7 +56,7 @@ use polkadot_parachain::primitives::{
};
use xcm::{latest::prelude::*, Version as XcmVersion, VersionedMultiLocation, VersionedXcm};
use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ConvertedConcreteAssetId,
EnsureXcmOrigin, FixedRateOfFungible, LocationInverter, ParentIsPreset,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
Expand Down Expand Up @@ -176,6 +179,8 @@ pub type LocationToAccountId = (
// Sibling parachain origins convert to AccountId via the `ParaId::into`.
SiblingParachainConvertsVia<Sibling, AccountId>,
AccountId32Aliases<RelayNetwork, AccountId>,
// Converts multilocation into a 32 byte hash for local `AccountId`s
Account32Hash<RelayNetwork, AccountId>,
);

/// This is the type to convert an (incoming) XCM origin into a local `Origin` instance,
Expand Down Expand Up @@ -241,6 +246,9 @@ match_types! {
pub type Barrier = (
// Allows local origin messages which call weight_credit >= weight_limit.
TakeWeightCredit,
// Allows execution of Transact XCM instruction from configurable set of origins
// as long as the message is in the format DescendOrigin + WithdrawAsset + BuyExecution
AllowTopLevelPaidExecutionDescendOriginFirst<Everything>,
// Allows non-local origin messages, for example from from the xcmp queue,
// which have the ability to deposit assets and pay for their own execution.
AllowTopLevelPaidExecutionFrom<Everything>,
Expand Down
140 changes: 138 additions & 2 deletions runtime/integration-tests/src/xcm_mock/xcm_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ use xcm_simulator::TestExt;
use super::{
parachain,
parachain::{
create_asset_location, create_asset_metadata, register_assets_on_parachain, AssetManager,
ParaTokenPerSecond, XcmExecutorConfig as ParaXcmExecutorConfig, PALLET_ASSET_INDEX,
create_asset_location, create_asset_metadata, register_assets_on_parachain, AccountId,
AssetManager, ParaTokenPerSecond, RelayNetwork, XcmExecutorConfig as ParaXcmExecutorConfig,
PALLET_ASSET_INDEX,
},
relay_chain, MockNet, ParaA, ParaB, ParaC, Relay, *,
};
Expand Down Expand Up @@ -133,6 +134,141 @@ fn dmp_transact_from_parent_should_pass_barrier() {
});
}

#[test]
fn xcmp_transact_from_sibling_tests() {
MockNet::reset();

let para_a_source_location = create_asset_location(1, PARA_A_ID);
let para_b_source_location = create_asset_location(1, PARA_B_ID);

let amount = INITIAL_BALANCE - 1000;

let para_a_asset_metadata = create_asset_metadata("ParaAToken", "ParaA", 18, 1, false, false);
let para_b_asset_metadata = create_asset_metadata("ParaBToken", "ParaB", 18, 1, false, false);

let _ = register_assets_on_parachain::<ParaA>(
&para_a_source_location,
&para_a_asset_metadata,
Some(0u128),
None,
);
let b_asset_id_on_a = register_assets_on_parachain::<ParaA>(
&para_b_source_location,
&para_b_asset_metadata,
Some(0u128),
None,
);

let _ = register_assets_on_parachain::<ParaB>(
&para_b_source_location,
&para_b_asset_metadata,
Some(0u128),
None,
);
let _ = register_assets_on_parachain::<ParaB>(
&para_a_source_location,
&para_a_asset_metadata,
Some(0u128),
None,
);

let remark = parachain::RuntimeCall::System(
frame_system::Call::<parachain::Runtime>::remark_with_event {
remark: vec![1, 2, 3],
},
);
let dummy_asset = MultiAsset {
id: Concrete(MultiLocation {
parents: 1,
interior: X1(Parachain(PARA_B_ID)),
}),
fun: Fungible(1000000000),
};
let dummy_assets = MultiAssets::from(vec![dummy_asset.clone()]);
let origin_location_interior = X1(AccountId32 {
network: Any,
id: ALICE.into(),
});
let alice_derived_account_on_b =
xcm_builder::Account32Hash::<RelayNetwork, AccountId>::convert_ref(MultiLocation {
parents: 1,
interior: X2(
Parachain(PARA_A_ID),
AccountId32 {
network: Any,
id: ALICE.into(),
},
),
})
.unwrap();

ParaB::execute_with(|| {
assert_ok!(pallet_balances::Pallet::<parachain::Runtime>::set_balance(
parachain::RuntimeOrigin::root(),
alice_derived_account_on_b.clone(),
amount,
0
));
});

ParaA::execute_with(|| {
assert_ok!(parachain::Assets::mint_into(
b_asset_id_on_a,
&ALICE,
amount
));
assert_ok!(ParachainPalletXcm::send_xcm(
Here,
(Parent, Parachain(PARA_B_ID)),
Xcm(vec![
DescendOrigin(origin_location_interior),
WithdrawAsset(dummy_assets.clone()),
BuyExecution {
fees: dummy_asset.clone(),
weight_limit: Unlimited,
},
Transact {
origin_type: OriginKind::SovereignAccount,
require_weight_at_most: INITIAL_BALANCE as u64,
call: remark.encode().into(),
}
]),
));
});

ParaB::execute_with(|| {
use parachain::{RuntimeEvent, System};
assert!(System::events().iter().any(|r| matches!(
r.event,
RuntimeEvent::System(frame_system::Event::Remarked { .. })
)));
});

ParaA::execute_with(|| {
assert_ok!(ParachainPalletXcm::send_xcm(
Here,
(Parent, Parachain(PARA_B_ID)),
Xcm(vec![Transact {
origin_type: OriginKind::SovereignAccount,
require_weight_at_most: INITIAL_BALANCE as u64,
call: remark.encode().into(),
}]),
));
});

ParaB::execute_with(|| {
use parachain::{RuntimeEvent, System};
assert!(System::events().iter().any(|r| matches!(
r.event,
RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail {
message_hash: _,
error: XcmError::Barrier,
weight: _
})
)));
});
}

#[test]
fn ump() {
MockNet::reset();
Expand Down
9 changes: 8 additions & 1 deletion runtime/manta/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ use xcm_builder::{
};
use xcm_executor::{traits::JustTry, Config, XcmExecutor};

use manta_primitives::xcm::AllowTopLevelPaidExecutionDescendOriginFirst;

parameter_types! {
pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4);
pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4);
Expand Down Expand Up @@ -87,9 +89,11 @@ pub type LocationToAccountId = (
SiblingParachainConvertsVia<Sibling, AccountId>,
// Straight up local `AccountId32` origins just alias directly to `AccountId`.
AccountId32Aliases<RelayNetwork, AccountId>,
// Converts multilocation into a 32 byte hash for local `AccountId`s
xcm_builder::Account32Hash<RelayNetwork, AccountId>,
);

/// This is the type to convert an (incoming) XCM origin into a local `RuntimeOrigin` instance,
/// This is the type to convert an (incoming) XCM origin into a local `Origin` instance,
/// ready for dispatching a transaction with Xcm's `Transact`.
/// It uses some Rust magic macro to do the pattern matching sequentially.
/// There is an `OriginKind` which can biases the kind of local `RuntimeOrigin` it will become.
Expand Down Expand Up @@ -153,6 +157,9 @@ match_types! {
pub type Barrier = (
// Allows local origin messages which call weight_credit >= weight_limit.
TakeWeightCredit,
// Allows execution of Transact XCM instruction from configurable set of origins
// as long as the message is in the format DescendOrigin + WithdrawAsset + BuyExecution
AllowTopLevelPaidExecutionDescendOriginFirst<Everything>,
// Allows non-local origin messages, for example from from the xcmp queue,
// which have the ability to deposit assets and pay for their own execution.
AllowTopLevelPaidExecutionFrom<Everything>,
Expand Down

0 comments on commit 5c37a5d

Please sign in to comment.