mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 11:01:01 +00:00
Improve Penpal runtime + emulated tests (#3543)
Issues addressed in this PR: - Improve *Penpal* runtime: - Properly handled received assets. Previously, it treated `(1, Here)` as the local native currency, whereas it should be treated as a `ForeignAsset`. This wasn't a great example of standard Parachain behaviour, as no Parachain treats the system asset as the local currency. - Remove `AllowExplicitUnpaidExecutionFrom` the system. Again, this wasn't a great example of standard Parachain behaviour. - Move duplicated `ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger` to `assets_common` crate. - Improve emulated tests: - Update *Penpal* tests to new runtime. - To simplify tests, register the reserve transferred, teleported, and system assets in *Penpal* and *AssetHub* genesis. This saves us from having to create the assets repeatedly for each test - Add missing test case: `reserve_transfer_assets_from_para_to_system_para`. - Cleanup. - Prevent integration tests crates imports from being re-exported, as they were polluting the `polkadot-sdk` docs. There is still a test case missing for reserve transfers: - Reserve transfer of system asset from *Parachain* to *Parachain* trough *AssetHub*. - This is not yet possible with `pallet-xcm` due to the reasons explained in https://github.com/paritytech/polkadot-sdk/pull/3339 --------- Co-authored-by: command-bot <>
This commit is contained in:
@@ -592,7 +592,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_assets_helpers_for_parachain {
|
||||
macro_rules! impl_assets_helpers_for_system_parachain {
|
||||
( $chain:ident, $relay_chain:ident ) => {
|
||||
$crate::impls::paste::paste! {
|
||||
impl<N: $crate::impls::Network> $chain<N> {
|
||||
@@ -630,38 +630,6 @@ macro_rules! impl_assets_helpers_for_parachain {
|
||||
$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,
|
||||
id: u32,
|
||||
beneficiary: $crate::impls::AccountId,
|
||||
amount_to_mint: u128,
|
||||
) {
|
||||
<Self as $crate::impls::TestExt>::execute_with(|| {
|
||||
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Assets::mint(
|
||||
signed_origin,
|
||||
id.clone().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>::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,
|
||||
@@ -727,8 +695,8 @@ macro_rules! impl_assets_helpers_for_parachain {
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_foreign_assets_helpers_for_parachain {
|
||||
( $chain:ident, $relay_chain:ident ) => {
|
||||
macro_rules! impl_assets_helpers_for_parachain {
|
||||
( $chain:ident) => {
|
||||
$crate::impls::paste::paste! {
|
||||
impl<N: $crate::impls::Network> $chain<N> {
|
||||
/// Create foreign assets using sudo `ForeignAssets::force_create()`
|
||||
@@ -803,6 +771,118 @@ macro_rules! impl_foreign_assets_helpers_for_parachain {
|
||||
);
|
||||
});
|
||||
}
|
||||
/// Create assets using sudo `Assets::force_create()`
|
||||
pub fn force_create_asset(
|
||||
id: u32,
|
||||
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>]>::Assets::force_create(
|
||||
sudo_origin,
|
||||
id.clone().into(),
|
||||
owner.clone().into(),
|
||||
is_sufficient,
|
||||
min_balance,
|
||||
)
|
||||
);
|
||||
assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.clone()));
|
||||
type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
|
||||
$crate::impls::assert_expected_events!(
|
||||
Self,
|
||||
vec![
|
||||
RuntimeEvent::<N>::Assets(
|
||||
$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_asset(signed_origin, id.clone(), beneficiary, amount);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mint assets making use of the assets pallet
|
||||
pub fn mint_asset(
|
||||
signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
|
||||
id: u32,
|
||||
beneficiary: $crate::impls::AccountId,
|
||||
amount_to_mint: u128,
|
||||
) {
|
||||
<Self as $crate::impls::TestExt>::execute_with(|| {
|
||||
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Assets::mint(
|
||||
signed_origin,
|
||||
id.clone().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>::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,
|
||||
},
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the encoded call for `create` from the assets pallet
|
||||
pub fn create_asset_call(
|
||||
asset_id: u32,
|
||||
min_balance: $crate::impls::Balance,
|
||||
admin: $crate::impls::AccountId,
|
||||
) -> $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,
|
||||
>::create {
|
||||
id: asset_id.into(),
|
||||
min_balance,
|
||||
admin: admin.into(),
|
||||
})
|
||||
.encode()
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Returns the encoded call for `create` from the foreign assets pallet
|
||||
pub fn create_foreign_asset_call(
|
||||
asset_id: $crate::impls::v3::Location,
|
||||
min_balance: $crate::impls::Balance,
|
||||
admin: $crate::impls::AccountId,
|
||||
) -> $crate::impls::DoubleEncoded<()> {
|
||||
use $crate::impls::{Chain, Encode};
|
||||
|
||||
<Self as Chain>::RuntimeCall::ForeignAssets($crate::impls::pallet_assets::Call::<
|
||||
<Self as Chain>::Runtime,
|
||||
$crate::impls::pallet_assets::Instance2,
|
||||
>::create {
|
||||
id: asset_id.into(),
|
||||
min_balance,
|
||||
admin: admin.into(),
|
||||
})
|
||||
.encode()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,17 +21,19 @@ pub use xcm_emulator;
|
||||
|
||||
// Substrate
|
||||
use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId;
|
||||
use frame_support::parameter_types;
|
||||
use grandpa::AuthorityId as GrandpaId;
|
||||
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||
use sp_consensus_babe::AuthorityId as BabeId;
|
||||
use sp_core::{sr25519, storage::Storage, Pair, Public};
|
||||
use sp_runtime::{
|
||||
traits::{IdentifyAccount, Verify},
|
||||
traits::{AccountIdConversion, IdentifyAccount, Verify},
|
||||
BuildStorage, MultiSignature,
|
||||
};
|
||||
|
||||
// Polakdot
|
||||
use parachains_common::BlockNumber;
|
||||
use polkadot_parachain_primitives::primitives::Sibling;
|
||||
use polkadot_runtime_parachains::configuration::HostConfiguration;
|
||||
|
||||
// Cumulus
|
||||
@@ -49,6 +51,25 @@ pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION;
|
||||
|
||||
type AccountPublic = <MultiSignature as Verify>::Signer;
|
||||
|
||||
// This asset is added to AH as Asset and reserved transfer between Parachain and AH
|
||||
pub const RESERVABLE_ASSET_ID: u32 = 1;
|
||||
// This asset is added to AH as ForeignAsset and teleported between Penpal and AH
|
||||
pub const TELEPORTABLE_ASSET_ID: u32 = 2;
|
||||
|
||||
pub const PENPAL_ID: u32 = 2000;
|
||||
pub const ASSETS_PALLET_ID: u8 = 50;
|
||||
|
||||
parameter_types! {
|
||||
pub PenpalTeleportableAssetLocation: xcm::v3::Location
|
||||
= xcm::v3::Location::new(1, [
|
||||
xcm::v3::Junction::Parachain(PENPAL_ID),
|
||||
xcm::v3::Junction::PalletInstance(ASSETS_PALLET_ID),
|
||||
xcm::v3::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()),
|
||||
]
|
||||
);
|
||||
pub PenpalSiblingSovereigAccount: AccountId = Sibling::from(PENPAL_ID).into_account_truncating();
|
||||
}
|
||||
|
||||
/// Helper function to generate a crypto pair from seed
|
||||
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
|
||||
TPublic::Pair::from_string(&format!("//{}", seed), None)
|
||||
|
||||
@@ -16,16 +16,26 @@
|
||||
pub use paste;
|
||||
|
||||
// Substrate
|
||||
pub use frame_support::{pallet_prelude::Weight, weights::WeightToFee};
|
||||
pub use pallet_assets;
|
||||
pub use pallet_balances;
|
||||
pub use pallet_message_queue;
|
||||
pub use pallet_xcm;
|
||||
|
||||
// Polkadot
|
||||
pub use xcm::prelude::{AccountId32, WeightLimit};
|
||||
pub use xcm::{
|
||||
prelude::{
|
||||
AccountId32, All, Asset, AssetId, BuyExecution, DepositAsset, ExpectTransactStatus,
|
||||
Fungible, Here, Location, MaybeErrorCode, OriginKind, RefundSurplus, Transact, Unlimited,
|
||||
VersionedXcm, WeightLimit, WithdrawAsset, Xcm,
|
||||
},
|
||||
v3::Location as V3Location,
|
||||
};
|
||||
|
||||
// Cumulus
|
||||
pub use asset_test_utils;
|
||||
pub use cumulus_pallet_xcmp_queue;
|
||||
pub use parachains_common::AccountId;
|
||||
pub use xcm_emulator::Chain;
|
||||
|
||||
#[macro_export]
|
||||
@@ -120,102 +130,3 @@ macro_rules! test_parachain_is_trusted_teleporter {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! include_penpal_create_foreign_asset_on_asset_hub {
|
||||
( $penpal:ident, $asset_hub:ident, $relay_ed:expr, $weight_to_fee:expr) => {
|
||||
$crate::impls::paste::paste! {
|
||||
pub fn penpal_create_foreign_asset_on_asset_hub(
|
||||
asset_id_on_penpal: u32,
|
||||
foreign_asset_at_asset_hub: v3::Location,
|
||||
ah_as_seen_by_penpal: Location,
|
||||
is_sufficient: bool,
|
||||
asset_owner: AccountId,
|
||||
prefund_amount: u128,
|
||||
) {
|
||||
use frame_support::weights::WeightToFee;
|
||||
let ah_check_account = $asset_hub::execute_with(|| {
|
||||
<$asset_hub as [<$asset_hub Pallet>]>::PolkadotXcm::check_account()
|
||||
});
|
||||
let penpal_check_account =
|
||||
$penpal::execute_with(|| <$penpal as [<$penpal Pallet>]>::PolkadotXcm::check_account());
|
||||
let penpal_as_seen_by_ah = $asset_hub::sibling_location_of($penpal::para_id());
|
||||
|
||||
// prefund SA of Penpal on AssetHub with enough native tokens to pay for creating
|
||||
// new foreign asset, also prefund CheckingAccount with ED, because teleported asset
|
||||
// itself might not be sufficient and CheckingAccount cannot be created otherwise
|
||||
let sov_penpal_on_ah = $asset_hub::sovereign_account_id_of(penpal_as_seen_by_ah.clone());
|
||||
$asset_hub::fund_accounts(vec![
|
||||
(sov_penpal_on_ah.clone().into(), $relay_ed * 100_000_000_000),
|
||||
(ah_check_account.clone().into(), $relay_ed * 1000),
|
||||
]);
|
||||
|
||||
// prefund SA of AssetHub on Penpal with native asset
|
||||
let sov_ah_on_penpal = $penpal::sovereign_account_id_of(ah_as_seen_by_penpal.clone());
|
||||
$penpal::fund_accounts(vec![
|
||||
(sov_ah_on_penpal.into(), $relay_ed * 1_000_000_000),
|
||||
(penpal_check_account.clone().into(), $relay_ed * 1000),
|
||||
]);
|
||||
|
||||
// Force create asset on $penpal and prefund [<$penpal Sender>]
|
||||
$penpal::force_create_and_mint_asset(
|
||||
asset_id_on_penpal,
|
||||
ASSET_MIN_BALANCE,
|
||||
is_sufficient,
|
||||
asset_owner,
|
||||
None,
|
||||
prefund_amount,
|
||||
);
|
||||
|
||||
let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000);
|
||||
// `OriginKind::Xcm` required by ForeignCreators pallet-assets origin filter
|
||||
let origin_kind = OriginKind::Xcm;
|
||||
let call_create_foreign_assets =
|
||||
<$asset_hub as Chain>::RuntimeCall::ForeignAssets(pallet_assets::Call::<
|
||||
<$asset_hub as Chain>::Runtime,
|
||||
pallet_assets::Instance2,
|
||||
>::create {
|
||||
id: foreign_asset_at_asset_hub,
|
||||
min_balance: ASSET_MIN_BALANCE,
|
||||
admin: sov_penpal_on_ah.into(),
|
||||
})
|
||||
.encode();
|
||||
let buy_execution_fee_amount = $weight_to_fee::weight_to_fee(
|
||||
&Weight::from_parts(10_100_000_000_000, 300_000),
|
||||
);
|
||||
let buy_execution_fee = Asset {
|
||||
id: AssetId(Location { parents: 1, interior: Here }),
|
||||
fun: Fungible(buy_execution_fee_amount),
|
||||
};
|
||||
let xcm = VersionedXcm::from(Xcm(vec![
|
||||
WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() },
|
||||
BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
|
||||
Transact { require_weight_at_most, origin_kind, call: call_create_foreign_assets.into() },
|
||||
ExpectTransactStatus(MaybeErrorCode::Success),
|
||||
RefundSurplus,
|
||||
DepositAsset { assets: All.into(), beneficiary: penpal_as_seen_by_ah },
|
||||
]));
|
||||
// Send XCM message from penpal => asset_hub
|
||||
let sudo_penpal_origin = <$penpal as Chain>::RuntimeOrigin::root();
|
||||
$penpal::execute_with(|| {
|
||||
assert_ok!(<$penpal as [<$penpal Pallet>]>::PolkadotXcm::send(
|
||||
sudo_penpal_origin.clone(),
|
||||
bx!(ah_as_seen_by_penpal.into()),
|
||||
bx!(xcm),
|
||||
));
|
||||
type RuntimeEvent = <$penpal as Chain>::RuntimeEvent;
|
||||
assert_expected_events!(
|
||||
$penpal,
|
||||
vec![
|
||||
RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
$asset_hub::execute_with(|| {
|
||||
type ForeignAssets = <$asset_hub as [<$asset_hub Pallet>]>::ForeignAssets;
|
||||
assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub));
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user