Newer
Older
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub use codec::{Decode, Encode};
pub use paste;
pub use crate::{
Ignacio Palacios
committed
xcm_helpers::xcm_transact_unpaid_execution, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD,
};
// Substrate
pub use frame_support::{
assert_ok,
Ignacio Palacios
committed
sp_runtime::AccountId32,
traits::fungibles::Inspect,
weights::{Weight, WeightMeter},
};
pub use pallet_assets;
pub use pallet_message_queue;
Ignacio Palacios
committed
pub use pallet_xcm;
use sp_core::Get;
Ignacio Palacios
committed
// Polkadot
pub use polkadot_runtime_parachains::{
dmp, hrmp,
inclusion::{AggregateMessageOrigin, UmpQueueId},
Ignacio Palacios
committed
pub use xcm::{
prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm},
v3::Error,
DoubleEncoded,
};
// Cumulus
pub use cumulus_pallet_parachain_system;
pub use cumulus_pallet_xcmp_queue;
pub use cumulus_primitives_core::{
Adrian Catangiu
committed
relay_chain::HrmpChannelId, DmpMessageHandler, Junction, Junctions, NetworkId, ParaId,
XcmpMessageHandler,
};
pub use parachains_common::{AccountId, Balance};
pub use xcm_emulator::{
assert_expected_events, bx, helpers::weight_within_threshold, BridgeMessage,
Ignacio Palacios
committed
BridgeMessageDispatchError, BridgeMessageHandler, Chain, Network, Parachain, RelayChain,
TestExt,
Ignacio Palacios
committed
// Bridges
use bp_messages::{
target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
LaneId, MessageKey, OutboundLaneData,
Ignacio Palacios
committed
use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult;
Adrian Catangiu
committed
use pallet_bridge_messages::{Config, OutboundLanes, Pallet};
pub use pallet_bridge_messages::{
Instance1 as BridgeMessagesInstance1, Instance2 as BridgeMessagesInstance2,
Instance3 as BridgeMessagesInstance3,
};
Adrian Catangiu
committed
pub struct BridgeHubMessageHandler<S, SI, T, TI> {
_marker: std::marker::PhantomData<(S, SI, T, TI)>,
}
struct LaneIdWrapper(LaneId);
impl From<LaneIdWrapper> for u32 {
fn from(lane_id: LaneIdWrapper) -> u32 {
u32::from_be_bytes(lane_id.0 .0)
}
}
impl From<u32> for LaneIdWrapper {
fn from(id: u32) -> LaneIdWrapper {
LaneIdWrapper(LaneId(id.to_be_bytes()))
}
}
Adrian Catangiu
committed
impl<S, SI, T, TI> BridgeMessageHandler for BridgeHubMessageHandler<S, SI, T, TI>
Adrian Catangiu
committed
S: Config<SI>,
SI: 'static,
T: Config<TI>,
TI: 'static,
<T as Config<TI>>::InboundPayload: From<Vec<u8>>,
<T as Config<TI>>::MessageDispatch:
MessageDispatch<DispatchLevelResult = XcmBlobMessageDispatchResult>,
{
fn get_source_outbound_messages() -> Vec<BridgeMessage> {
// get the source active outbound lanes
let active_lanes = S::ActiveOutboundLanes::get();
let mut messages: Vec<BridgeMessage> = Default::default();
// collect messages from `OutboundMessages` for each active outbound lane in the source
for lane in active_lanes {
Adrian Catangiu
committed
let latest_generated_nonce = OutboundLanes::<S, SI>::get(lane).latest_generated_nonce;
let latest_received_nonce = OutboundLanes::<S, SI>::get(lane).latest_received_nonce;
(latest_received_nonce + 1..=latest_generated_nonce).for_each(|nonce| {
Adrian Catangiu
committed
let encoded_payload: Vec<u8> = Pallet::<S, SI>::outbound_message_data(*lane, nonce)
.expect("Bridge message does not exist")
.into();
let payload = Vec::<u8>::decode(&mut &encoded_payload[..])
.expect("Decodign XCM message failed");
let id: u32 = LaneIdWrapper(*lane).into();
let message = BridgeMessage { id, nonce, payload };
messages.push(message);
});
}
messages
}
fn dispatch_target_inbound_message(
message: BridgeMessage,
) -> Result<(), BridgeMessageDispatchError> {
type TargetMessageDispatch<T, I> = <T as Config<I>>::MessageDispatch;
type InboundPayload<T, I> = <T as Config<I>>::InboundPayload;
let lane_id = LaneIdWrapper::from(message.id).0;
let nonce = message.nonce;
let payload = Ok(From::from(message.payload));
// Directly dispatch outbound messages assuming everything is correct
// and bypassing the `Relayers` and `InboundLane` logic
Adrian Catangiu
committed
let dispatch_result = TargetMessageDispatch::<T, TI>::dispatch(DispatchMessage {
key: MessageKey { lane_id, nonce },
Adrian Catangiu
committed
data: DispatchMessageData::<InboundPayload<T, TI>> { payload },
});
let result = match dispatch_result.dispatch_level_result {
XcmBlobMessageDispatchResult::Dispatched => Ok(()),
XcmBlobMessageDispatchResult::InvalidPayload => Err(BridgeMessageDispatchError(
Box::new(XcmBlobMessageDispatchResult::InvalidPayload),
)),
XcmBlobMessageDispatchResult::NotDispatched(e) => Err(BridgeMessageDispatchError(
Box::new(XcmBlobMessageDispatchResult::NotDispatched(e)),
)),
};
result
}
fn notify_source_message_delivery(lane_id: u32) {
Adrian Catangiu
committed
let data = OutboundLanes::<S, SI>::get(LaneIdWrapper::from(lane_id).0);
let new_data = OutboundLaneData {
oldest_unpruned_nonce: data.oldest_unpruned_nonce + 1,
latest_received_nonce: data.latest_received_nonce + 1,
..data
};
Adrian Catangiu
committed
OutboundLanes::<S, SI>::insert(LaneIdWrapper::from(lane_id).0, new_data);
#[macro_export]
macro_rules! impl_accounts_helpers_for_relay_chain {
( $chain:ident ) => {
$crate::impls::paste::paste! {
Ignacio Palacios
committed
impl<N: $crate::impls::Network> $chain<N> {
/// Fund a set of accounts with a balance
pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) {
<Self as $crate::impls::TestExt>::execute_with(|| {
for account in accounts {
Ignacio Palacios
committed
$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::Balances::force_set_balance(
<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
account.0.into(),
account.1,
));
}
});
}
/// Fund a sovereign account based on its Parachain Id
Ignacio Palacios
committed
pub fn fund_para_sovereign(amount: $crate::impls::Balance, para_id: $crate::impls::ParaId) -> $crate::impls::AccountId32 {
let sovereign_account = <Self as $crate::impls::RelayChain>::sovereign_account_id_of_child_para(para_id);
Self::fund_accounts(vec![(sovereign_account.clone(), amount)]);
sovereign_account
}
}
}
};
}
#[macro_export]
macro_rules! impl_assert_events_helpers_for_relay_chain {
( $chain:ident ) => {
$crate::impls::paste::paste! {
Ignacio Palacios
committed
type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
Ignacio Palacios
committed
impl<N: $crate::impls::Network> $chain<N> {
/// Asserts a dispatchable is completely executed and XCM sent
pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::XcmPallet(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) }
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
},
]
);
}
/// Asserts a dispatchable is incompletely executed and XCM sent
pub fn assert_xcm_pallet_attempted_incomplete(
expected_weight: Option<$crate::impls::Weight>,
expected_error: Option<$crate::impls::Error>,
$crate::impls::assert_expected_events!(
Self,
vec![
// Dispatchable is properly executed and XCM message sent
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::XcmPallet(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) }
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
error: *error == expected_error.unwrap_or(*error),
},
]
);
}
/// Asserts a XCM message is sent
pub fn assert_xcm_pallet_sent() {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::XcmPallet($crate::impls::pallet_xcm::Event::Sent { .. }) => {},
]
);
}
/// Asserts a XCM from System Parachain is succesfully received and proccessed
pub fn assert_ump_queue_processed(
expected_success: bool,
expected_id: Option<$crate::impls::ParaId>,
expected_weight: Option<$crate::impls::Weight>,
$crate::impls::assert_expected_events!(
Self,
vec![
// XCM is succesfully received and proccessed
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
origin: $crate::impls::AggregateMessageOrigin::Ump($crate::impls::UmpQueueId::Para(id)),
weight_used,
success,
..
}) => {
id: *id == expected_id.unwrap_or(*id),
weight_used: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight_used),
*weight_used
),
success: *success == expected_success,
},
]
);
}
}
}
};
}
#[macro_export]
macro_rules! impl_hrmp_channels_helpers_for_relay_chain {
( $chain:ident ) => {
$crate::impls::paste::paste! {
Ignacio Palacios
committed
impl<N: $crate::impls::Network> $chain<N> {
/// Init open channel request with another Parachain
pub fn init_open_channel_call(
recipient_para_id: $crate::impls::ParaId,
max_capacity: u32,
max_message_size: u32,
) -> $crate::impls::DoubleEncoded<()> {
use $crate::impls::Encode;
<Self as $crate::impls::Chain>::RuntimeCall::Hrmp($crate::impls::hrmp::Call::<
<Self as $crate::impls::Chain>::Runtime,
>::hrmp_init_open_channel {
recipient: recipient_para_id,
proposed_max_capacity: max_capacity,
proposed_max_message_size: max_message_size,
})
.encode()
.into()
}
/// Recipient Parachain accept the open request from another Parachain
pub fn accept_open_channel_call(sender_para_id: $crate::impls::ParaId) -> $crate::impls::DoubleEncoded<()> {
use $crate::impls::Encode;
<Self as $crate::impls::Chain>::RuntimeCall::Hrmp($crate::impls::hrmp::Call::<
<Self as $crate::impls::Chain>::Runtime,
>::hrmp_accept_open_channel {
sender: sender_para_id,
})
.encode()
.into()
}
/// A root origin force to open a channel between two Parachains
pub fn force_process_hrmp_open(sender: $crate::impls::ParaId, recipient: $crate::impls::ParaId) {
use $crate::impls::Chain;
<Self as $crate::impls::TestExt>::execute_with(|| {
let relay_root_origin = <Self as Chain>::RuntimeOrigin::root();
// Force process HRMP open channel requests without waiting for the next session
Ignacio Palacios
committed
$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::Hrmp::force_process_hrmp_open(
relay_root_origin,
0
));
let channel_id = $crate::impls::HrmpChannelId { sender, recipient };
let hrmp_channel_exist = $crate::impls::hrmp::HrmpChannels::<
<Self as Chain>::Runtime,
>::contains_key(&channel_id);
// Check the HRMP channel has been successfully registrered
assert!(hrmp_channel_exist)
});
}
}
}
};
}
#[macro_export]
macro_rules! impl_send_transact_helpers_for_relay_chain {
( $chain:ident ) => {
$crate::impls::paste::paste! {
Ignacio Palacios
committed
impl<N: $crate::impls::Network> $chain<N> {
/// A root origin (as governance) sends `xcm::Transact` with `UnpaidExecution` and encoded `call` to child parachain.
pub fn send_unpaid_transact_to_parachain_as_root(
recipient: $crate::impls::ParaId,
call: $crate::impls::DoubleEncoded<()>
) {
use $crate::impls::{bx, Chain, RelayChain};
<Self as $crate::impls::TestExt>::execute_with(|| {
let root_origin = <Self as Chain>::RuntimeOrigin::root();
let destination: $crate::impls::MultiLocation = <Self as RelayChain>::child_location_of(recipient);
let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser);
// Send XCM `Transact`
Ignacio Palacios
committed
$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::XcmPallet::send(
root_origin,
bx!(destination.into()),
bx!(xcm),
));
Self::assert_xcm_pallet_sent();
});
}
}
}
};
}
#[macro_export]
macro_rules! impl_accounts_helpers_for_parachain {
( $chain:ident ) => {
$crate::impls::paste::paste! {
Ignacio Palacios
committed
impl<N: $crate::impls::Network> $chain<N> {
/// Fund a set of accounts with a balance
pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) {
<Self as $crate::impls::TestExt>::execute_with(|| {
for account in accounts {
Ignacio Palacios
committed
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Balances::force_set_balance(
<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
account.0.into(),
account.1,
));
}
});
}
Adrian Catangiu
committed
/// Return local sovereign account of `para_id` on other `network_id`
pub fn sovereign_account_of_parachain_on_other_global_consensus(
network_id: $crate::impls::NetworkId,
para_id: $crate::impls::ParaId,
) -> $crate::impls::AccountId {
let remote_location = $crate::impls::MultiLocation {
parents: 2,
interior: $crate::impls::Junctions::X2(
$crate::impls::Junction::GlobalConsensus(network_id),
$crate::impls::Junction::Parachain(para_id.into()),
),
};
<Self as $crate::impls::TestExt>::execute_with(|| {
Self::sovereign_account_id_of(remote_location)
})
}
}
}
};
}
#[macro_export]
macro_rules! impl_assert_events_helpers_for_parachain {
Adrian Catangiu
committed
( $chain:ident ) => {
$crate::impls::paste::paste! {
Ignacio Palacios
committed
type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
Ignacio Palacios
committed
impl<N: $crate::impls::Network> $chain<N> {
/// Asserts a dispatchable is completely executed and XCM sent
pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) }
Adrian Catangiu
committed
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
},
]
);
}
/// Asserts a dispatchable is incompletely executed and XCM sent
pub fn assert_xcm_pallet_attempted_incomplete(
expected_weight: Option<$crate::impls::Weight>,
expected_error: Option<$crate::impls::Error>,
$crate::impls::assert_expected_events!(
Self,
vec![
// Dispatchable is properly executed and XCM message sent
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) }
Adrian Catangiu
committed
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
error: *error == expected_error.unwrap_or(*error),
},
]
);
}
/// Asserts a dispatchable throws and error when trying to be sent
pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::Error>) {
$crate::impls::assert_expected_events!(
Self,
vec![
// Execution fails in the origin with `Barrier`
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Error(error) }
) => {
error: *error == expected_error.unwrap_or(*error),
},
]
);
}
/// Asserts a XCM message is sent
pub fn assert_xcm_pallet_sent() {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::PolkadotXcm($crate::impls::pallet_xcm::Event::Sent { .. }) => {},
]
);
}
/// Asserts a XCM message is sent to Relay Chain
pub fn assert_parachain_system_ump_sent() {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::ParachainSystem(
$crate::impls::cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
) => {},
]
);
}
/// Asserts a XCM from Relay Chain is completely executed
pub fn assert_dmp_queue_complete(expected_weight: Option<$crate::impls::Weight>) {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
success: true, weight_used: weight, ..
Adrian Catangiu
committed
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
},
]
);
}
/// Asserts a XCM from Relay Chain is incompletely executed
pub fn assert_dmp_queue_incomplete(
expected_weight: Option<$crate::impls::Weight>,
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
success: false, weight_used: weight, ..
Adrian Catangiu
committed
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
},
]
);
}
/// Asserts a XCM from Relay Chain is executed with error
pub fn assert_dmp_queue_error() {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::ProcessingFailed {
},
]
);
}
/// Asserts a XCM from another Parachain is completely executed
pub fn assert_xcmp_queue_success(expected_weight: Option<$crate::impls::Weight>) {
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }
Adrian Catangiu
committed
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
},
]
);
}
}
}
};
}
#[macro_export]
Adrian Catangiu
committed
macro_rules! impl_assets_helpers_for_parachain {
( $chain:ident, $relay_chain:ident ) => {
$crate::impls::paste::paste! {
Ignacio Palacios
committed
impl<N: $crate::impls::Network> $chain<N> {
/// Returns the encoded call for `force_create` from the assets pallet
pub fn force_create_asset_call(
asset_id: u32,
owner: $crate::impls::AccountId,
is_sufficient: bool,
min_balance: $crate::impls::Balance,
) -> $crate::impls::DoubleEncoded<()> {
use $crate::impls::{Chain, Encode};
<Self as Chain>::RuntimeCall::Assets($crate::impls::pallet_assets::Call::<
<Self as Chain>::Runtime,
$crate::impls::pallet_assets::Instance1,
>::force_create {
id: asset_id.into(),
owner: owner.into(),
is_sufficient,
min_balance,
})
.encode()
.into()
}
/// Returns a `VersionedXcm` for `force_create` from the assets pallet
pub fn force_create_asset_xcm(
origin_kind: $crate::impls::OriginKind,
asset_id: u32,
owner: $crate::impls::AccountId,
is_sufficient: bool,
min_balance: $crate::impls::Balance,
) -> $crate::impls::VersionedXcm<()> {
let call = Self::force_create_asset_call(asset_id, owner, is_sufficient, min_balance);
$crate::impls::xcm_transact_unpaid_execution(call, origin_kind)
}
/// Mint assets making use of the assets pallet
pub fn mint_asset(
signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
beneficiary: $crate::impls::AccountId,
amount_to_mint: u128,
) {
<Self as $crate::impls::TestExt>::execute_with(|| {
Ignacio Palacios
committed
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Assets::mint(
signed_origin,
id.into(),
beneficiary.clone().into(),
amount_to_mint
));
Ignacio Palacios
committed
type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
$crate::impls::assert_expected_events!(
Self,
vec![
Adrian Catangiu
committed
RuntimeEvent::<N>::Assets(
$crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }
) => {
asset_id: *asset_id == id,
owner: *owner == beneficiary.clone().into(),
amount: *amount == amount_to_mint,
},
]
);
});
}
/// Force create and mint assets making use of the assets pallet
pub fn force_create_and_mint_asset(
id: u32,
min_balance: u128,
is_sufficient: bool,
asset_owner: $crate::impls::AccountId,
dmp_weight_threshold: Option<$crate::impls::Weight>,
amount_to_mint: u128,
) {
use $crate::impls::Chain;
// Force create asset
Self::force_create_asset_from_relay_as_root(
id,
min_balance,
is_sufficient,
asset_owner.clone(),
dmp_weight_threshold
// Mint asset for System Parachain's sender
let signed_origin = <Self as Chain>::RuntimeOrigin::signed(asset_owner.clone());
Self::mint_asset(signed_origin, id, asset_owner, amount_to_mint);
}
/// Relay Chain sends `Transact` instruction with `force_create_asset` to Parachain with `Assets` instance of `pallet_assets` .
pub fn force_create_asset_from_relay_as_root(
id: u32,
min_balance: u128,
is_sufficient: bool,
asset_owner: $crate::impls::AccountId,
dmp_weight_threshold: Option<$crate::impls::Weight>,
) {
use $crate::impls::{Parachain, Inspect, TestExt};
Ignacio Palacios
committed
<$relay_chain<N>>::send_unpaid_transact_to_parachain_as_root(
Self::para_id(),
Self::force_create_asset_call(id, asset_owner.clone(), is_sufficient, min_balance),
);
// Receive XCM message in Assets Parachain
Self::execute_with(|| {
Ignacio Palacios
committed
type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
Self::assert_dmp_queue_complete(dmp_weight_threshold);
$crate::impls::assert_expected_events!(
Self,
vec![
Ignacio Palacios
committed
RuntimeEvent::<N>::Assets($crate::impls::pallet_assets::Event::ForceCreated { asset_id, owner }) => {
asset_id: *asset_id == id,
},
]
);
Ignacio Palacios
committed
assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.into()));
});
}
}
}
};
}
Adrian Catangiu
committed
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
#[macro_export]
macro_rules! impl_foreign_assets_helpers_for_parachain {
( $chain:ident, $relay_chain:ident ) => {
$crate::impls::paste::paste! {
impl<N: $crate::impls::Network> $chain<N> {
/// Create foreign assets using sudo `ForeignAssets::force_create()`
pub fn force_create_foreign_asset(
id: $crate::impls::MultiLocation,
owner: $crate::impls::AccountId,
is_sufficient: bool,
min_balance: u128,
prefund_accounts: Vec<($crate::impls::AccountId, u128)>,
) {
use $crate::impls::Inspect;
let sudo_origin = <$chain<N> as $crate::impls::Chain>::RuntimeOrigin::root();
<Self as $crate::impls::TestExt>::execute_with(|| {
$crate::impls::assert_ok!(
<Self as [<$chain ParaPallet>]>::ForeignAssets::force_create(
sudo_origin,
id,
owner.clone().into(),
is_sufficient,
min_balance,
)
);
assert!(<Self as [<$chain ParaPallet>]>::ForeignAssets::asset_exists(id));
type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
$crate::impls::assert_expected_events!(
Self,
vec![
RuntimeEvent::<N>::ForeignAssets(
$crate::impls::pallet_assets::Event::ForceCreated {
asset_id,
..
}
) => { asset_id: *asset_id == id, },
]
);
});
for (beneficiary, amount) in prefund_accounts.into_iter() {
let signed_origin =
<$chain<N> as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone());
Self::mint_foreign_asset(signed_origin, id, beneficiary, amount);
}
}
/// Mint assets making use of the ForeignAssets pallet-assets instance
pub fn mint_foreign_asset(
signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
id: $crate::impls::MultiLocation,
beneficiary: $crate::impls::AccountId,
amount_to_mint: u128,
) {
<Self as $crate::impls::TestExt>::execute_with(|| {
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::ForeignAssets::mint(
signed_origin,
id.into(),
beneficiary.clone().into(),
amount_to_mint
));
type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
$crate::impls::assert_expected_events!(
Self,
vec![
RuntimeEvent::<N>::ForeignAssets(
$crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }
) => {
asset_id: *asset_id == id,
owner: *owner == beneficiary.clone().into(),
amount: *amount == amount_to_mint,
},
]
);
});
}
}
}
};
}