mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
Add Support for Foreign Assets (#2133)
* add foreign assets to westmint * add foreign assets to statemine * use updated api for ensure origin trait * Assets/ForeignAssets tests and fixes (#2167) * Test for create and transfer `TrustBackedAssets` with AssetTransactor * Test for transfer `local Currency` with AssetTransactor * Test for create foreign assets (covers foreign relaychain currency) * Added `ForeignFungiblesTransactor` and test for transfer `ForeignAssets` with AssetTransactor * Removed unused `pub const Local: MultiLocation` * Changed `ParaId -> Sibling` for `SiblingParachainConvertsVia` * Test for create foreign assets (covers local sibling parachain assets) * Reverted stuff for ForeignCreators from different global consensus (moved to transfer asset branch) * Refactor `weight_limit` for `execute_xcm` * Added test for `set_metadata` by ForeignCreator with `xcm::Transact(set_metadata)` * Renamed `receive_teleported_asset_works` -> `receive_teleported_asset_for_native_asset_works` * Allow `ForeignCreators` only for sibling parachains * Unify ReservedDmpWeight/ReservedXcmpWeight usage * Removed hack - replaced with `MatchedConvertedConcreteId` * Refactor `ForeignCreators` to assets-common * Add `ReceiveTeleportedAsset` test * Change test - `Utility::batch` -> Multiple `xcm::Transact` * Reusing the same deposits as for TrustBackedAssets * missing `try_successful_origin` ? * Finished `ForeignAssets` for westmint (converter, FungiblesApi, tests) * Refactoring tests - receive_teleported_asset_for_native_asset_works * ForeignAssets for statemine + refactored `receive_teleported_asset_from_foreign_creator_works` * Add `ForeignAssets` to statemine `FungiblesApi` * Add `asset_transactor_transfer_with_local_consensus_currency_works` to all runtimes * Added `asset_transactor_transfer_with_trust_backed_assets_works` test * Added `asset_transactor_transfer_with_foreign_assets_works` * Fix `missing `try_successful_origin` in implementation` * Added `create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works` * Added `ExpectTransactStatus` check * Small rename * Extended `test_assets_balances_api_works` with ForeignAssets for `statemine` * PR fixes * Update parachains/runtimes/assets/test-utils/src/test_cases.rs --------- Co-authored-by: parity-processbot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Added `StartsWithExplicitGlobalConsensus` to ignores (#2338) * Update parachains/runtimes/assets/common/src/lib.rs Co-authored-by: Gavin Wood <gavin@parity.io> * include mint and burn in SafeCallFilter * include mint and burn in SafeCallFilter (statemine) * clarify doc * Fix compilation (moved trait `InspectMetadata`) * Fix test * Extended test for `teleport` from/to relaychain + `CheckingAccount` (Part I) * Extended test for `teleport` from/to foreign parachain + `CheckingAccount` (Part II) * Fixed TODO - `NonLocal` for `ForeignAssets` * Changed `NonLocal` to `NoChecking` * Fix weight in test --------- Co-authored-by: parity-processbot <> Co-authored-by: muharem <ismailov.m.h@gmail.com> Co-authored-by: Branislav Kontur <bkontur@gmail.com> Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
@@ -1,11 +1,27 @@
|
||||
use frame_support::traits::GenesisBuild;
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
use frame_support::traits::OriginTrait;
|
||||
use cumulus_primitives_core::{AbridgedHrmpChannel, ParaId, PersistedValidationData};
|
||||
use cumulus_primitives_parachain_inherent::ParachainInherentData;
|
||||
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
|
||||
use frame_support::{
|
||||
dispatch::{DispatchResult, RawOrigin, UnfilteredDispatchable},
|
||||
inherent::{InherentData, ProvideInherent},
|
||||
traits::{GenesisBuild, OriginTrait},
|
||||
weights::Weight,
|
||||
};
|
||||
use parachains_common::AccountId;
|
||||
use polkadot_parachain::primitives::{HrmpChannelId, RelayChainBlockNumber};
|
||||
use sp_consensus_aura::AURA_ENGINE_ID;
|
||||
use sp_core::Encode;
|
||||
use sp_runtime::{Digest, DigestItem};
|
||||
use xcm::{
|
||||
latest::{MultiAsset, MultiLocation, XcmContext, XcmHash},
|
||||
prelude::{Concrete, Fungible, Outcome, XcmError, XcmVersion},
|
||||
};
|
||||
use xcm_executor::{traits::TransactAsset, Assets};
|
||||
|
||||
pub mod test_cases;
|
||||
pub use test_cases::CollatorSessionKeys;
|
||||
|
||||
pub type BalanceOf<Runtime> = <Runtime as pallet_balances::Config>::Balance;
|
||||
pub type AccountIdOf<Runtime> = <Runtime as frame_system::Config>::AccountId;
|
||||
@@ -14,7 +30,11 @@ pub type SessionKeysOf<Runtime> = <Runtime as pallet_session::Config>::Keys;
|
||||
|
||||
// Basic builder based on balances, collators and pallet_sessopm
|
||||
pub struct ExtBuilder<
|
||||
Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config,
|
||||
Runtime: frame_system::Config
|
||||
+ pallet_balances::Config
|
||||
+ pallet_session::Config
|
||||
+ pallet_xcm::Config
|
||||
+ parachain_info::Config,
|
||||
> {
|
||||
// endowed accounts with balances
|
||||
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
||||
@@ -22,19 +42,40 @@ pub struct ExtBuilder<
|
||||
collators: Vec<AccountIdOf<Runtime>>,
|
||||
// keys added to pallet session
|
||||
keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
|
||||
// safe xcm version for pallet_xcm
|
||||
safe_xcm_version: Option<XcmVersion>,
|
||||
// para id
|
||||
para_id: Option<ParaId>,
|
||||
_runtime: PhantomData<Runtime>,
|
||||
}
|
||||
|
||||
impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config> Default
|
||||
for ExtBuilder<Runtime>
|
||||
impl<
|
||||
Runtime: frame_system::Config
|
||||
+ pallet_balances::Config
|
||||
+ pallet_session::Config
|
||||
+ pallet_xcm::Config
|
||||
+ parachain_info::Config,
|
||||
> Default for ExtBuilder<Runtime>
|
||||
{
|
||||
fn default() -> ExtBuilder<Runtime> {
|
||||
ExtBuilder { balances: vec![], collators: vec![], keys: vec![], _runtime: PhantomData }
|
||||
ExtBuilder {
|
||||
balances: vec![],
|
||||
collators: vec![],
|
||||
keys: vec![],
|
||||
safe_xcm_version: None,
|
||||
para_id: None,
|
||||
_runtime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::Config>
|
||||
ExtBuilder<Runtime>
|
||||
impl<
|
||||
Runtime: frame_system::Config
|
||||
+ pallet_balances::Config
|
||||
+ pallet_session::Config
|
||||
+ pallet_xcm::Config
|
||||
+ parachain_info::Config,
|
||||
> ExtBuilder<Runtime>
|
||||
{
|
||||
pub fn with_balances(
|
||||
mut self,
|
||||
@@ -56,6 +97,21 @@ impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::C
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_tracing(self) -> Self {
|
||||
frame_support::sp_tracing::try_init_simple();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_safe_xcm_version(mut self, safe_xcm_version: XcmVersion) -> Self {
|
||||
self.safe_xcm_version = Some(safe_xcm_version);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_para_id(mut self, para_id: ParaId) -> Self {
|
||||
self.para_id = Some(para_id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> sp_io::TestExternalities
|
||||
where
|
||||
Runtime:
|
||||
@@ -64,6 +120,20 @@ impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::C
|
||||
{
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
||||
|
||||
<pallet_xcm::GenesisConfig as GenesisBuild<Runtime>>::assimilate_storage(
|
||||
&pallet_xcm::GenesisConfig { safe_xcm_version: self.safe_xcm_version },
|
||||
&mut t,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some(para_id) = self.para_id {
|
||||
<parachain_info::GenesisConfig as frame_support::traits::GenesisBuild<Runtime>>::assimilate_storage(
|
||||
¶chain_info::GenesisConfig { parachain_id: para_id },
|
||||
&mut t,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pallet_balances::GenesisConfig::<Runtime> { balances: self.balances.into() }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
@@ -132,3 +202,184 @@ where
|
||||
<Runtime as frame_system::Config>::RuntimeOrigin::signed(account_id.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<XcmConfig: xcm_executor::Config> RuntimeHelper<XcmConfig> {
|
||||
pub fn do_transfer(
|
||||
from: MultiLocation,
|
||||
to: MultiLocation,
|
||||
(asset, amount): (MultiLocation, u128),
|
||||
) -> Result<Assets, XcmError> {
|
||||
<XcmConfig::AssetTransactor as TransactAsset>::transfer_asset(
|
||||
&MultiAsset { id: Concrete(asset), fun: Fungible(amount) },
|
||||
&from,
|
||||
&to,
|
||||
// We aren't able to track the XCM that initiated the fee deposit, so we create a
|
||||
// fake message hash here
|
||||
&XcmContext::with_message_hash([0; 32]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config> RuntimeHelper<Runtime> {
|
||||
pub fn do_teleport_assets<HrmpChannelOpener>(
|
||||
origin: <Runtime as frame_system::Config>::RuntimeOrigin,
|
||||
dest: MultiLocation,
|
||||
beneficiary: MultiLocation,
|
||||
(asset, amount): (MultiLocation, u128),
|
||||
open_hrmp_channel: Option<(u32, u32)>,
|
||||
) -> DispatchResult
|
||||
where
|
||||
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
|
||||
Call = cumulus_pallet_parachain_system::Call<Runtime>,
|
||||
>,
|
||||
{
|
||||
// open hrmp (if needed)
|
||||
if let Some((source_para_id, target_para_id)) = open_hrmp_channel {
|
||||
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
|
||||
source_para_id.into(),
|
||||
target_para_id.into(),
|
||||
);
|
||||
}
|
||||
|
||||
// do teleport
|
||||
<pallet_xcm::Pallet<Runtime>>::teleport_assets(
|
||||
origin,
|
||||
Box::new(dest.into()),
|
||||
Box::new(beneficiary.into()),
|
||||
Box::new((Concrete(asset), amount).into()),
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum XcmReceivedFrom {
|
||||
Parent,
|
||||
Sibling,
|
||||
}
|
||||
|
||||
impl<ParachainSystem: cumulus_pallet_parachain_system::Config> RuntimeHelper<ParachainSystem> {
|
||||
pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight {
|
||||
use frame_support::traits::Get;
|
||||
match from {
|
||||
XcmReceivedFrom::Parent => ParachainSystem::ReservedDmpWeight::get(),
|
||||
XcmReceivedFrom::Sibling => ParachainSystem::ReservedXcmpWeight::get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: frame_system::Config + pallet_xcm::Config> RuntimeHelper<Runtime> {
|
||||
pub fn assert_pallet_xcm_event_outcome(
|
||||
unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
|
||||
assert_outcome: fn(Outcome),
|
||||
) {
|
||||
let outcome = <frame_system::Pallet<Runtime>>::events()
|
||||
.into_iter()
|
||||
.filter_map(|e| unwrap_pallet_xcm_event(e.event.encode()))
|
||||
.find_map(|e| match e {
|
||||
pallet_xcm::Event::Attempted(outcome) => Some(outcome),
|
||||
_ => None,
|
||||
});
|
||||
match outcome {
|
||||
Some(outcome) => assert_outcome(outcome),
|
||||
None => assert!(false, "No `pallet_xcm::Event::Attempted(outcome)` event found!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: frame_system::Config + cumulus_pallet_xcmp_queue::Config> RuntimeHelper<Runtime> {
|
||||
pub fn xcmp_queue_message_sent(
|
||||
unwrap_xcmp_queue_event: Box<
|
||||
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
|
||||
>,
|
||||
) -> Option<XcmHash> {
|
||||
<frame_system::Pallet<Runtime>>::events()
|
||||
.into_iter()
|
||||
.filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
|
||||
.find_map(|e| match e {
|
||||
cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } => message_hash,
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_metadata<Fungibles, AccountId>(
|
||||
asset_id: impl Into<Fungibles::AssetId> + Copy,
|
||||
expected_name: &str,
|
||||
expected_symbol: &str,
|
||||
expected_decimals: u8,
|
||||
) where
|
||||
Fungibles: frame_support::traits::tokens::fungibles::metadata::Inspect<AccountId>
|
||||
+ frame_support::traits::tokens::fungibles::Inspect<AccountId>,
|
||||
{
|
||||
assert_eq!(Fungibles::name(asset_id.into()), Vec::from(expected_name),);
|
||||
assert_eq!(Fungibles::symbol(asset_id.into()), Vec::from(expected_symbol),);
|
||||
assert_eq!(Fungibles::decimals(asset_id.into()), expected_decimals);
|
||||
}
|
||||
|
||||
pub fn assert_total<Fungibles, AccountId>(
|
||||
asset_id: impl Into<Fungibles::AssetId> + Copy,
|
||||
expected_total_issuance: impl Into<Fungibles::Balance>,
|
||||
expected_active_issuance: impl Into<Fungibles::Balance>,
|
||||
) where
|
||||
Fungibles: frame_support::traits::tokens::fungibles::metadata::Inspect<AccountId>
|
||||
+ frame_support::traits::tokens::fungibles::Inspect<AccountId>,
|
||||
{
|
||||
assert_eq!(Fungibles::total_issuance(asset_id.into()), expected_total_issuance.into());
|
||||
assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into());
|
||||
}
|
||||
|
||||
/// Helper function which emulates opening HRMP channel which is needed for `XcmpQueue` to pass
|
||||
pub fn mock_open_hrmp_channel<
|
||||
C: cumulus_pallet_parachain_system::Config,
|
||||
T: ProvideInherent<Call = cumulus_pallet_parachain_system::Call<C>>,
|
||||
>(
|
||||
sender: ParaId,
|
||||
recipient: ParaId,
|
||||
) {
|
||||
let n = 1_u32;
|
||||
let mut sproof_builder = RelayStateSproofBuilder::default();
|
||||
sproof_builder.para_id = sender;
|
||||
sproof_builder.hrmp_channels.insert(
|
||||
HrmpChannelId { sender, recipient },
|
||||
AbridgedHrmpChannel {
|
||||
max_capacity: 10,
|
||||
max_total_size: 10_000_000_u32,
|
||||
max_message_size: 10_000_000_u32,
|
||||
msg_count: 0,
|
||||
total_size: 0_u32,
|
||||
mqc_head: None,
|
||||
},
|
||||
);
|
||||
sproof_builder.hrmp_egress_channel_index = Some(vec![recipient]);
|
||||
|
||||
let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof();
|
||||
let vfp = PersistedValidationData {
|
||||
relay_parent_number: n as RelayChainBlockNumber,
|
||||
relay_parent_storage_root,
|
||||
..Default::default()
|
||||
};
|
||||
// It is insufficient to push the validation function params
|
||||
// to storage; they must also be included in the inherent data.
|
||||
let inherent_data = {
|
||||
let mut inherent_data = InherentData::default();
|
||||
let system_inherent_data = ParachainInherentData {
|
||||
validation_data: vfp.clone(),
|
||||
relay_chain_state,
|
||||
downward_messages: Default::default(),
|
||||
horizontal_messages: Default::default(),
|
||||
};
|
||||
inherent_data
|
||||
.put_data(
|
||||
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
|
||||
&system_inherent_data,
|
||||
)
|
||||
.expect("failed to put VFP inherent");
|
||||
inherent_data
|
||||
};
|
||||
|
||||
// execute the block
|
||||
T::create_inherent(&inherent_data)
|
||||
.expect("got an inherent")
|
||||
.dispatch_bypass_filter(RawOrigin::None.into())
|
||||
.expect("dispatch succeeded");
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user