mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 08:11:03 +00:00
Asset conversion nits (#2860)
* [asset-conv] Unused Balances type
* [asset-conv] native asset change
* Dedicated `AssetBalance` type for `pallet_assets` instances
* Improved local vs foreign asset handling + test for not allowing pool_assets in pool
* Removed `into_multiasset_id`
* Fix
* Refactor
* Fixed create_pool for benchmark with LocalAndForeignAssets (finally found it)
* ".git/.scripts/commands/fmt/fmt.sh"
* Revert
* fmt
* Migrates pools with `MultiLocation { parents: 0, interior: Here }` to `MultiLocation { parents: 1, interior: Here }`
* Allow `set_storage` for `AllowMultiAssetPools` / `LiquidityWithdrawalFee`
* Benchmarks work
* Removed comment + more defensive migration
* `T::Currency::transfer` -> `Balances::transfer_all` in migration
* Change pool_id in migration
* Update parachains/runtimes/assets/asset-hub-westend/src/lib.rs
* Bump substrate (manually)
* Bump polkadot
* Fixes from polkadot + clippy
* Fix for xcm-emulator tests (thank you Nacho)
---------
Co-authored-by: command-bot <>
Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com>
This commit is contained in:
Generated
+266
-263
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -50,7 +50,7 @@ fn reserve_transfer_native_asset_from_relay_to_assets() {
|
|||||||
Kusama,
|
Kusama,
|
||||||
vec![
|
vec![
|
||||||
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => {
|
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => {
|
||||||
weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(754_244_000, 0), *weight),
|
weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(630_092_000, 6196), *weight),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
+1
-1
@@ -50,7 +50,7 @@ fn reserve_transfer_native_asset_from_relay_to_assets() {
|
|||||||
Polkadot,
|
Polkadot,
|
||||||
vec![
|
vec![
|
||||||
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => {
|
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => {
|
||||||
weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(2_000_000_000, 0), *weight),
|
weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(686_043_000, 6196), *weight),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ description = "Asset Hub Westend runtime integration tests with xcm-emulator"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false }
|
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false }
|
||||||
|
assert_matches = "1.5.0"
|
||||||
|
|
||||||
# Substrate
|
# Substrate
|
||||||
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
+1
-1
@@ -50,7 +50,7 @@ fn reserve_transfer_native_asset_from_relay_to_assets() {
|
|||||||
Westend,
|
Westend,
|
||||||
vec![
|
vec![
|
||||||
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => {
|
RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { outcome: Outcome::Complete(weight) }) => {
|
||||||
weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(731_495_000, 0), *weight),
|
weight: weight_within_threshold((REF_TIME_THRESHOLD, PROOF_SIZE_THRESHOLD), Weight::from_parts(629_384_000, 6196), *weight),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
+40
-2
@@ -1,12 +1,13 @@
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
use frame_support::{instances::Instance2, BoundedVec};
|
use frame_support::{instances::Instance2, BoundedVec};
|
||||||
|
use sp_runtime::{DispatchError, ModuleError};
|
||||||
use xcm_emulator::Parachain;
|
use xcm_emulator::Parachain;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn swap_locally_on_chain_using_local_assets() {
|
fn swap_locally_on_chain_using_local_assets() {
|
||||||
const ASSET_ID: u32 = 1;
|
const ASSET_ID: u32 = 1;
|
||||||
|
|
||||||
let asset_native = Box::new(MultiLocation { parents: 0, interior: Here });
|
let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get());
|
||||||
let asset_one = Box::new(MultiLocation {
|
let asset_one = Box::new(MultiLocation {
|
||||||
parents: 0,
|
parents: 0,
|
||||||
interior: X2(PalletInstance(50), GeneralIndex(ASSET_ID.into())),
|
interior: X2(PalletInstance(50), GeneralIndex(ASSET_ID.into())),
|
||||||
@@ -99,7 +100,7 @@ fn swap_locally_on_chain_using_foreign_assets() {
|
|||||||
use frame_support::weights::WeightToFee;
|
use frame_support::weights::WeightToFee;
|
||||||
|
|
||||||
const ASSET_ID: u32 = 1;
|
const ASSET_ID: u32 = 1;
|
||||||
let asset_native = Box::new(MultiLocation { parents: 0, interior: Here });
|
let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get());
|
||||||
|
|
||||||
let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation {
|
let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation {
|
||||||
parents: 1,
|
parents: 1,
|
||||||
@@ -305,3 +306,40 @@ fn swap_locally_on_chain_using_foreign_assets() {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cannot_create_pool_from_pool_assets() {
|
||||||
|
const ASSET_ID: u32 = 1;
|
||||||
|
|
||||||
|
let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get());
|
||||||
|
let mut asset_one = asset_hub_westend_runtime::xcm_config::PoolAssetsPalletLocation::get();
|
||||||
|
asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets");
|
||||||
|
|
||||||
|
AssetHubWestend::execute_with(|| {
|
||||||
|
let pool_owner_account_id = asset_hub_westend_runtime::AssetConversionOrigin::get();
|
||||||
|
|
||||||
|
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::PoolAssets::create(
|
||||||
|
<AssetHubWestend as Parachain>::RuntimeOrigin::signed(pool_owner_account_id.clone()),
|
||||||
|
ASSET_ID.into(),
|
||||||
|
pool_owner_account_id.clone().into(),
|
||||||
|
1000,
|
||||||
|
));
|
||||||
|
assert!(<AssetHubWestend as AssetHubWestendPallet>::PoolAssets::asset_exists(ASSET_ID));
|
||||||
|
|
||||||
|
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::PoolAssets::mint(
|
||||||
|
<AssetHubWestend as Parachain>::RuntimeOrigin::signed(pool_owner_account_id),
|
||||||
|
ASSET_ID.into(),
|
||||||
|
AssetHubWestendSender::get().into(),
|
||||||
|
3_000_000_000_000,
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_matches::assert_matches!(
|
||||||
|
<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool(
|
||||||
|
<AssetHubWestend as Parachain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
|
||||||
|
asset_native.clone(),
|
||||||
|
Box::new(asset_one),
|
||||||
|
),
|
||||||
|
Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset"))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ decl_test_parachains! {
|
|||||||
PolkadotXcm: asset_hub_westend_runtime::PolkadotXcm,
|
PolkadotXcm: asset_hub_westend_runtime::PolkadotXcm,
|
||||||
Assets: asset_hub_westend_runtime::Assets,
|
Assets: asset_hub_westend_runtime::Assets,
|
||||||
ForeignAssets: asset_hub_westend_runtime::ForeignAssets,
|
ForeignAssets: asset_hub_westend_runtime::ForeignAssets,
|
||||||
|
PoolAssets: asset_hub_westend_runtime::PoolAssets,
|
||||||
AssetConversion: asset_hub_westend_runtime::AssetConversion,
|
AssetConversion: asset_hub_westend_runtime::AssetConversion,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1139,7 +1139,7 @@ impl_runtime_apis! {
|
|||||||
MultiAsset { fun: Fungible(UNITS), id: Concrete(KsmLocation::get()) },
|
MultiAsset { fun: Fungible(UNITS), id: Concrete(KsmLocation::get()) },
|
||||||
));
|
));
|
||||||
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
||||||
|
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||||
@@ -1147,6 +1147,7 @@ impl_runtime_apis! {
|
|||||||
|
|
||||||
type CheckedAccount = CheckedAccount;
|
type CheckedAccount = CheckedAccount;
|
||||||
type TrustedTeleporter = TrustedTeleporter;
|
type TrustedTeleporter = TrustedTeleporter;
|
||||||
|
type TrustedReserve = TrustedReserve;
|
||||||
|
|
||||||
fn get_multi_asset() -> MultiAsset {
|
fn get_multi_asset() -> MultiAsset {
|
||||||
MultiAsset {
|
MultiAsset {
|
||||||
|
|||||||
@@ -1121,6 +1121,7 @@ impl_runtime_apis! {
|
|||||||
MultiAsset { fun: Fungible(UNITS), id: Concrete(DotLocation::get()) },
|
MultiAsset { fun: Fungible(UNITS), id: Concrete(DotLocation::get()) },
|
||||||
));
|
));
|
||||||
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
||||||
|
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||||
@@ -1128,6 +1129,7 @@ impl_runtime_apis! {
|
|||||||
|
|
||||||
type CheckedAccount = CheckedAccount;
|
type CheckedAccount = CheckedAccount;
|
||||||
type TrustedTeleporter = TrustedTeleporter;
|
type TrustedTeleporter = TrustedTeleporter;
|
||||||
|
type TrustedReserve = TrustedReserve;
|
||||||
|
|
||||||
fn get_multi_asset() -> MultiAsset {
|
fn get_multi_asset() -> MultiAsset {
|
||||||
MultiAsset {
|
MultiAsset {
|
||||||
|
|||||||
@@ -28,8 +28,13 @@ pub mod constants;
|
|||||||
mod weights;
|
mod weights;
|
||||||
pub mod xcm_config;
|
pub mod xcm_config;
|
||||||
|
|
||||||
use crate::xcm_config::{TrustBackedAssetsPalletLocation, UniversalLocation};
|
use crate::xcm_config::{
|
||||||
use assets_common::local_and_foreign_assets::{LocalAndForeignAssets, MultiLocationConverter};
|
LocalAndForeignAssetsMultiLocationMatcher, TrustBackedAssetsPalletLocation,
|
||||||
|
};
|
||||||
|
use assets_common::{
|
||||||
|
local_and_foreign_assets::{LocalAndForeignAssets, MultiLocationConverter},
|
||||||
|
AssetIdForTrustBackedAssetsConvert,
|
||||||
|
};
|
||||||
use codec::{Decode, Encode, MaxEncodedLen};
|
use codec::{Decode, Encode, MaxEncodedLen};
|
||||||
use constants::{currency::*, fee::WeightToFee};
|
use constants::{currency::*, fee::WeightToFee};
|
||||||
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
|
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
|
||||||
@@ -300,9 +305,13 @@ impl pallet_asset_conversion::Config for Runtime {
|
|||||||
type Balance = Balance;
|
type Balance = Balance;
|
||||||
type HigherPrecisionBalance = sp_core::U256;
|
type HigherPrecisionBalance = sp_core::U256;
|
||||||
type Currency = Balances;
|
type Currency = Balances;
|
||||||
type AssetBalance = <Self as pallet_balances::Config>::Balance;
|
type AssetBalance = Balance;
|
||||||
type AssetId = MultiLocation;
|
type AssetId = MultiLocation;
|
||||||
type Assets = LocalAndForeignAssets<Assets, ForeignAssets, TrustBackedAssetsPalletLocation>;
|
type Assets = LocalAndForeignAssets<
|
||||||
|
Assets,
|
||||||
|
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
|
||||||
|
ForeignAssets,
|
||||||
|
>;
|
||||||
type PoolAssets = PoolAssets;
|
type PoolAssets = PoolAssets;
|
||||||
type PoolAssetId = u32;
|
type PoolAssetId = u32;
|
||||||
type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam
|
type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam
|
||||||
@@ -314,11 +323,12 @@ impl pallet_asset_conversion::Config for Runtime {
|
|||||||
type MaxSwapPathLength = ConstU32<4>;
|
type MaxSwapPathLength = ConstU32<4>;
|
||||||
|
|
||||||
type MultiAssetId = Box<MultiLocation>;
|
type MultiAssetId = Box<MultiLocation>;
|
||||||
type MultiAssetIdConverter = MultiLocationConverter<Balances, UniversalLocation>;
|
type MultiAssetIdConverter =
|
||||||
|
MultiLocationConverter<WestendLocation, LocalAndForeignAssetsMultiLocationMatcher>;
|
||||||
|
|
||||||
type MintMinLiquidity = ConstU128<100>;
|
type MintMinLiquidity = ConstU128<100>;
|
||||||
|
|
||||||
type WeightInfo = ();
|
type WeightInfo = weights::pallet_asset_conversion::WeightInfo<Runtime>;
|
||||||
|
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
type BenchmarkHelper =
|
type BenchmarkHelper =
|
||||||
@@ -659,7 +669,11 @@ impl pallet_collator_selection::Config for Runtime {
|
|||||||
|
|
||||||
impl pallet_asset_conversion_tx_payment::Config for Runtime {
|
impl pallet_asset_conversion_tx_payment::Config for Runtime {
|
||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
type Fungibles = LocalAndForeignAssets<Assets, ForeignAssets, TrustBackedAssetsPalletLocation>;
|
type Fungibles = LocalAndForeignAssets<
|
||||||
|
Assets,
|
||||||
|
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
|
||||||
|
ForeignAssets,
|
||||||
|
>;
|
||||||
type OnChargeAssetTransaction = AssetConversionAdapter<Balances, AssetConversion>;
|
type OnChargeAssetTransaction = AssetConversionAdapter<Balances, AssetConversion>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,6 +849,8 @@ pub type Migrations = (
|
|||||||
pallet_nfts::migration::v1::MigrateToV1<Runtime>,
|
pallet_nfts::migration::v1::MigrateToV1<Runtime>,
|
||||||
// unreleased
|
// unreleased
|
||||||
pallet_collator_selection::migration::v1::MigrateToV1<Runtime>,
|
pallet_collator_selection::migration::v1::MigrateToV1<Runtime>,
|
||||||
|
// unreleased
|
||||||
|
migrations::NativeAssetParents0ToParents1Migration<Runtime>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Executive: handles dispatch to the various modules.
|
/// Executive: handles dispatch to the various modules.
|
||||||
@@ -1240,7 +1256,7 @@ impl_runtime_apis! {
|
|||||||
MultiAsset { fun: Fungible(UNITS), id: Concrete(WestendLocation::get()) },
|
MultiAsset { fun: Fungible(UNITS), id: Concrete(WestendLocation::get()) },
|
||||||
));
|
));
|
||||||
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
||||||
|
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||||
@@ -1248,6 +1264,7 @@ impl_runtime_apis! {
|
|||||||
|
|
||||||
type CheckedAccount = CheckedAccount;
|
type CheckedAccount = CheckedAccount;
|
||||||
type TrustedTeleporter = TrustedTeleporter;
|
type TrustedTeleporter = TrustedTeleporter;
|
||||||
|
type TrustedReserve = TrustedReserve;
|
||||||
|
|
||||||
fn get_multi_asset() -> MultiAsset {
|
fn get_multi_asset() -> MultiAsset {
|
||||||
MultiAsset {
|
MultiAsset {
|
||||||
@@ -1360,3 +1377,120 @@ cumulus_pallet_parachain_system::register_validate_block! {
|
|||||||
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
|
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
|
||||||
CheckInherents = CheckInherents,
|
CheckInherents = CheckInherents,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod migrations {
|
||||||
|
use super::*;
|
||||||
|
use frame_support::{
|
||||||
|
pallet_prelude::Get,
|
||||||
|
traits::{
|
||||||
|
fungibles::{Inspect, Mutate},
|
||||||
|
tokens::Preservation,
|
||||||
|
OnRuntimeUpgrade, OriginTrait,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use parachains_common::impls::AccountIdOf;
|
||||||
|
use sp_runtime::{traits::StaticLookup, Saturating};
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
/// Temporary migration because of bug with native asset, it can be removed once applied on `AssetHubWestend`.
|
||||||
|
/// Migrates pools with `MultiLocation { parents: 0, interior: Here }` to `MultiLocation { parents: 1, interior: Here }`
|
||||||
|
pub struct NativeAssetParents0ToParents1Migration<T>(sp_std::marker::PhantomData<T>);
|
||||||
|
impl<
|
||||||
|
T: pallet_asset_conversion::Config<
|
||||||
|
MultiAssetId = Box<MultiLocation>,
|
||||||
|
AssetId = MultiLocation,
|
||||||
|
>,
|
||||||
|
> OnRuntimeUpgrade for NativeAssetParents0ToParents1Migration<T>
|
||||||
|
where
|
||||||
|
<T as pallet_asset_conversion::Config>::PoolAssetId: Into<u32>,
|
||||||
|
AccountIdOf<Runtime>: Into<[u8; 32]>,
|
||||||
|
<T as frame_system::Config>::AccountId:
|
||||||
|
Into<<<T as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
|
||||||
|
<<T as frame_system::Config>::Lookup as StaticLookup>::Source:
|
||||||
|
From<<T as frame_system::Config>::AccountId>,
|
||||||
|
sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
|
||||||
|
{
|
||||||
|
fn on_runtime_upgrade() -> Weight {
|
||||||
|
let invalid_native_asset = MultiLocation { parents: 0, interior: Here };
|
||||||
|
let valid_native_asset = WestendLocation::get();
|
||||||
|
|
||||||
|
let mut reads: u64 = 1;
|
||||||
|
let mut writes: u64 = 0;
|
||||||
|
|
||||||
|
// migrate pools with invalid native asset
|
||||||
|
let pools = pallet_asset_conversion::Pools::<T>::iter().collect::<Vec<_>>();
|
||||||
|
reads.saturating_accrue(1);
|
||||||
|
for (old_pool_id, pool_info) in pools {
|
||||||
|
let old_pool_account =
|
||||||
|
pallet_asset_conversion::Pallet::<T>::get_pool_account(&old_pool_id);
|
||||||
|
reads.saturating_accrue(1);
|
||||||
|
let pool_asset_id = pool_info.lp_token.clone();
|
||||||
|
if old_pool_id.0.as_ref() != &invalid_native_asset {
|
||||||
|
// skip, if ok
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix new account
|
||||||
|
let new_pool_id = pallet_asset_conversion::Pallet::<T>::get_pool_id(
|
||||||
|
Box::new(valid_native_asset),
|
||||||
|
old_pool_id.1.clone(),
|
||||||
|
);
|
||||||
|
let new_pool_account =
|
||||||
|
pallet_asset_conversion::Pallet::<T>::get_pool_account(&new_pool_id);
|
||||||
|
frame_system::Pallet::<T>::inc_providers(&new_pool_account);
|
||||||
|
reads.saturating_accrue(2);
|
||||||
|
writes.saturating_accrue(1);
|
||||||
|
|
||||||
|
// move currency
|
||||||
|
let _ = Balances::transfer_all(
|
||||||
|
RuntimeOrigin::signed(sp_runtime::AccountId32::from(old_pool_account.clone())),
|
||||||
|
sp_runtime::AccountId32::from(new_pool_account.clone()).into(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
reads.saturating_accrue(2);
|
||||||
|
writes.saturating_accrue(2);
|
||||||
|
|
||||||
|
// move LP token
|
||||||
|
let _ = T::PoolAssets::transfer(
|
||||||
|
pool_asset_id.clone(),
|
||||||
|
&old_pool_account,
|
||||||
|
&new_pool_account,
|
||||||
|
T::PoolAssets::balance(pool_asset_id.clone(), &old_pool_account),
|
||||||
|
Preservation::Expendable,
|
||||||
|
);
|
||||||
|
reads.saturating_accrue(1);
|
||||||
|
writes.saturating_accrue(2);
|
||||||
|
|
||||||
|
// change the ownership of LP token
|
||||||
|
let _ = pallet_assets::Pallet::<Runtime, PoolAssetsInstance>::transfer_ownership(
|
||||||
|
RuntimeOrigin::signed(sp_runtime::AccountId32::from(old_pool_account.clone())),
|
||||||
|
pool_asset_id.into(),
|
||||||
|
sp_runtime::AccountId32::from(new_pool_account.clone()).into(),
|
||||||
|
);
|
||||||
|
reads.saturating_accrue(1);
|
||||||
|
writes.saturating_accrue(2);
|
||||||
|
|
||||||
|
// move LocalOrForeignAssets
|
||||||
|
let _ = T::Assets::transfer(
|
||||||
|
*old_pool_id.1.as_ref(),
|
||||||
|
&old_pool_account,
|
||||||
|
&new_pool_account,
|
||||||
|
T::Assets::balance(*old_pool_id.1.as_ref(), &old_pool_account),
|
||||||
|
Preservation::Expendable,
|
||||||
|
);
|
||||||
|
reads.saturating_accrue(1);
|
||||||
|
writes.saturating_accrue(2);
|
||||||
|
|
||||||
|
// dec providers for old account
|
||||||
|
let _ = frame_system::Pallet::<T>::dec_providers(&old_pool_account);
|
||||||
|
writes.saturating_accrue(1);
|
||||||
|
|
||||||
|
// change pool key
|
||||||
|
pallet_asset_conversion::Pools::<T>::insert(new_pool_id, pool_info);
|
||||||
|
pallet_asset_conversion::Pools::<T>::remove(old_pool_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
T::DbWeight::get().reads_writes(reads, writes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ pub mod block_weights;
|
|||||||
pub mod cumulus_pallet_xcmp_queue;
|
pub mod cumulus_pallet_xcmp_queue;
|
||||||
pub mod extrinsic_weights;
|
pub mod extrinsic_weights;
|
||||||
pub mod frame_system;
|
pub mod frame_system;
|
||||||
|
pub mod pallet_asset_conversion;
|
||||||
pub mod pallet_assets_foreign;
|
pub mod pallet_assets_foreign;
|
||||||
pub mod pallet_assets_local;
|
pub mod pallet_assets_local;
|
||||||
pub mod pallet_assets_pool;
|
pub mod pallet_assets_pool;
|
||||||
|
|||||||
+157
@@ -0,0 +1,157 @@
|
|||||||
|
// Copyright Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Cumulus is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Autogenerated weights for `pallet_asset_conversion`
|
||||||
|
//!
|
||||||
|
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||||
|
//! DATE: 2023-07-18, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||||
|
//! WORST CASE MAP SIZE: `1000000`
|
||||||
|
//! HOSTNAME: `bkontur-ThinkPad-P14s-Gen-2i`, CPU: `11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz`
|
||||||
|
//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024
|
||||||
|
|
||||||
|
// Executed Command:
|
||||||
|
// ./target/release/polkadot-parachain
|
||||||
|
// benchmark
|
||||||
|
// pallet
|
||||||
|
// --chain=asset-hub-westend-dev
|
||||||
|
// --wasm-execution=compiled
|
||||||
|
// --pallet=pallet_asset_conversion
|
||||||
|
// --no-storage-info
|
||||||
|
// --no-median-slopes
|
||||||
|
// --no-min-squares
|
||||||
|
// --extrinsic=*
|
||||||
|
// --steps=2
|
||||||
|
// --repeat=1
|
||||||
|
// --json
|
||||||
|
// --header=./file_header.txt
|
||||||
|
// --output=./parachains/runtimes/assets/asset-hub-westend/src/weights/
|
||||||
|
|
||||||
|
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
#![allow(unused_parens)]
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
|
use frame_support::{traits::Get, weights::Weight};
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
/// Weight functions for `pallet_asset_conversion`.
|
||||||
|
pub struct WeightInfo<T>(PhantomData<T>);
|
||||||
|
impl<T: frame_system::Config> pallet_asset_conversion::WeightInfo for WeightInfo<T> {
|
||||||
|
/// Storage: `AssetConversion::Pools` (r:1 w:1)
|
||||||
|
/// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0)
|
||||||
|
/// Proof: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0)
|
||||||
|
/// Storage: `System::Account` (r:2 w:1)
|
||||||
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Account` (r:1 w:1)
|
||||||
|
/// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Asset` (r:1 w:1)
|
||||||
|
/// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1)
|
||||||
|
/// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `PoolAssets::Asset` (r:1 w:1)
|
||||||
|
/// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `PoolAssets::Account` (r:1 w:1)
|
||||||
|
/// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||||
|
fn create_pool() -> Weight {
|
||||||
|
// Proof Size summary in bytes:
|
||||||
|
// Measured: `480`
|
||||||
|
// Estimated: `6196`
|
||||||
|
// Minimum execution time: 115_870_000 picoseconds.
|
||||||
|
Weight::from_parts(115_870_000, 0)
|
||||||
|
.saturating_add(Weight::from_parts(0, 6196))
|
||||||
|
.saturating_add(T::DbWeight::get().reads(9))
|
||||||
|
.saturating_add(T::DbWeight::get().writes(7))
|
||||||
|
}
|
||||||
|
/// Storage: `AssetConversion::Pools` (r:1 w:0)
|
||||||
|
/// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `System::Account` (r:1 w:1)
|
||||||
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Asset` (r:1 w:1)
|
||||||
|
/// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Account` (r:2 w:2)
|
||||||
|
/// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `PoolAssets::Asset` (r:1 w:1)
|
||||||
|
/// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `PoolAssets::Account` (r:2 w:2)
|
||||||
|
/// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||||
|
fn add_liquidity() -> Weight {
|
||||||
|
// Proof Size summary in bytes:
|
||||||
|
// Measured: `1117`
|
||||||
|
// Estimated: `7404`
|
||||||
|
// Minimum execution time: 183_835_000 picoseconds.
|
||||||
|
Weight::from_parts(183_835_000, 0)
|
||||||
|
.saturating_add(Weight::from_parts(0, 7404))
|
||||||
|
.saturating_add(T::DbWeight::get().reads(8))
|
||||||
|
.saturating_add(T::DbWeight::get().writes(7))
|
||||||
|
}
|
||||||
|
/// Storage: `AssetConversion::Pools` (r:1 w:0)
|
||||||
|
/// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `System::Account` (r:1 w:1)
|
||||||
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Asset` (r:1 w:1)
|
||||||
|
/// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Account` (r:2 w:2)
|
||||||
|
/// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `PoolAssets::Asset` (r:1 w:1)
|
||||||
|
/// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0)
|
||||||
|
/// Proof: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0)
|
||||||
|
/// Storage: `PoolAssets::Account` (r:1 w:1)
|
||||||
|
/// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||||
|
fn remove_liquidity() -> Weight {
|
||||||
|
// Proof Size summary in bytes:
|
||||||
|
// Measured: `1106`
|
||||||
|
// Estimated: `7404`
|
||||||
|
// Minimum execution time: 166_533_000 picoseconds.
|
||||||
|
Weight::from_parts(166_533_000, 0)
|
||||||
|
.saturating_add(Weight::from_parts(0, 7404))
|
||||||
|
.saturating_add(T::DbWeight::get().reads(8))
|
||||||
|
.saturating_add(T::DbWeight::get().writes(6))
|
||||||
|
}
|
||||||
|
/// Storage: `ForeignAssets::Asset` (r:2 w:2)
|
||||||
|
/// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Account` (r:4 w:4)
|
||||||
|
/// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `System::Account` (r:2 w:2)
|
||||||
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
|
fn swap_exact_tokens_for_tokens() -> Weight {
|
||||||
|
// Proof Size summary in bytes:
|
||||||
|
// Measured: `1148`
|
||||||
|
// Estimated: `13818`
|
||||||
|
// Minimum execution time: 206_165_000 picoseconds.
|
||||||
|
Weight::from_parts(206_165_000, 0)
|
||||||
|
.saturating_add(Weight::from_parts(0, 13818))
|
||||||
|
.saturating_add(T::DbWeight::get().reads(8))
|
||||||
|
.saturating_add(T::DbWeight::get().writes(8))
|
||||||
|
}
|
||||||
|
/// Storage: `System::Account` (r:2 w:2)
|
||||||
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Asset` (r:2 w:2)
|
||||||
|
/// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`)
|
||||||
|
/// Storage: `ForeignAssets::Account` (r:4 w:4)
|
||||||
|
/// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`)
|
||||||
|
fn swap_tokens_for_exact_tokens() -> Weight {
|
||||||
|
// Proof Size summary in bytes:
|
||||||
|
// Measured: `1148`
|
||||||
|
// Estimated: `13818`
|
||||||
|
// Minimum execution time: 208_694_000 picoseconds.
|
||||||
|
Weight::from_parts(208_694_000, 0)
|
||||||
|
.saturating_add(Weight::from_parts(0, 13818))
|
||||||
|
.saturating_add(T::DbWeight::get().reads(8))
|
||||||
|
.saturating_add(T::DbWeight::get().writes(8))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,12 @@ use super::{
|
|||||||
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
||||||
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
||||||
};
|
};
|
||||||
use crate::ForeignAssets;
|
use crate::{AllowMultiAssetPools, ForeignAssets, LiquidityWithdrawalFee};
|
||||||
use assets_common::matching::{
|
use assets_common::{
|
||||||
|
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
|
||||||
|
matching::{
|
||||||
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
|
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
match_types, parameter_types,
|
match_types, parameter_types,
|
||||||
@@ -163,6 +166,25 @@ pub type PoolFungiblesTransactor = FungiblesAdapter<
|
|||||||
pub type AssetTransactors =
|
pub type AssetTransactors =
|
||||||
(CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor);
|
(CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor);
|
||||||
|
|
||||||
|
/// Simple `MultiLocation` matcher for Local and Foreign asset `MultiLocation`.
|
||||||
|
pub struct LocalAndForeignAssetsMultiLocationMatcher;
|
||||||
|
impl MatchesLocalAndForeignAssetsMultiLocation for LocalAndForeignAssetsMultiLocationMatcher {
|
||||||
|
fn is_local(location: &MultiLocation) -> bool {
|
||||||
|
use assets_common::fungible_conversion::MatchesMultiLocation;
|
||||||
|
TrustBackedAssetsConvertedConcreteId::contains(location)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_foreign(location: &MultiLocation) -> bool {
|
||||||
|
use assets_common::fungible_conversion::MatchesMultiLocation;
|
||||||
|
ForeignAssetsConvertedConcreteId::contains(location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Contains<MultiLocation> for LocalAndForeignAssetsMultiLocationMatcher {
|
||||||
|
fn contains(location: &MultiLocation) -> bool {
|
||||||
|
Self::is_local(location) || Self::is_foreign(location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
|
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
|
||||||
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
|
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
|
||||||
/// biases the kind of local `Origin` it will become.
|
/// biases the kind of local `Origin` it will become.
|
||||||
@@ -217,6 +239,16 @@ impl Contains<RuntimeCall> for SafeCallFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow to change dedicated storage items (called by governance-like)
|
||||||
|
match call {
|
||||||
|
RuntimeCall::System(frame_system::Call::set_storage { items })
|
||||||
|
if items.iter().any(|(k, _)| {
|
||||||
|
k.eq(&AllowMultiAssetPools::key()) | k.eq(&LiquidityWithdrawalFee::key())
|
||||||
|
}) =>
|
||||||
|
return true,
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
|
||||||
matches!(
|
matches!(
|
||||||
call,
|
call,
|
||||||
RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) |
|
RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) |
|
||||||
@@ -540,7 +572,8 @@ pub struct BenchmarkMultiLocationConverter<SelfParaId> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
impl<SelfParaId> pallet_asset_conversion::BenchmarkHelper<MultiLocation>
|
impl<SelfParaId>
|
||||||
|
pallet_asset_conversion::BenchmarkHelper<MultiLocation, sp_std::boxed::Box<MultiLocation>>
|
||||||
for BenchmarkMultiLocationConverter<SelfParaId>
|
for BenchmarkMultiLocationConverter<SelfParaId>
|
||||||
where
|
where
|
||||||
SelfParaId: Get<ParaId>,
|
SelfParaId: Get<ParaId>,
|
||||||
@@ -555,4 +588,8 @@ where
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn multiasset_id(asset_id: u32) -> sp_std::boxed::Box<MultiLocation> {
|
||||||
|
sp_std::boxed::Box::new(Self::asset_id(asset_id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ use asset_hub_westend_runtime::{
|
|||||||
AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf,
|
AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf,
|
||||||
WestendLocation,
|
WestendLocation,
|
||||||
},
|
},
|
||||||
MetadataDepositBase, MetadataDepositPerByte, RuntimeCall, RuntimeEvent,
|
AllowMultiAssetPools, LiquidityWithdrawalFee, MetadataDepositBase, MetadataDepositPerByte,
|
||||||
|
RuntimeCall, RuntimeEvent,
|
||||||
};
|
};
|
||||||
use asset_test_utils::{CollatorSessionKeys, ExtBuilder, RuntimeHelper, XcmReceivedFrom};
|
use asset_test_utils::{CollatorSessionKeys, ExtBuilder, RuntimeHelper, XcmReceivedFrom};
|
||||||
use codec::{Decode, DecodeLimit, Encode};
|
use codec::{Decode, DecodeLimit, Encode};
|
||||||
@@ -39,7 +40,10 @@ use frame_support::{
|
|||||||
weights::{Weight, WeightToFee as WeightToFeeT},
|
weights::{Weight, WeightToFee as WeightToFeeT},
|
||||||
};
|
};
|
||||||
use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance};
|
use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance};
|
||||||
use sp_runtime::traits::MaybeEquivalence;
|
use sp_runtime::{
|
||||||
|
traits::{CheckedAdd, CheckedSub, MaybeEquivalence},
|
||||||
|
Permill,
|
||||||
|
};
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH};
|
use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH};
|
||||||
use xcm_executor::{
|
use xcm_executor::{
|
||||||
@@ -652,3 +656,39 @@ fn plain_receive_teleported_asset_works() {
|
|||||||
assert_eq!(outcome.ensure_complete(), Ok(()));
|
assert_eq!(outcome.ensure_complete(), Ok(()));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn change_allow_multi_asset_pools_by_governance_works() {
|
||||||
|
asset_test_utils::test_cases::change_storage_constant_by_governance_works::<
|
||||||
|
Runtime,
|
||||||
|
AllowMultiAssetPools,
|
||||||
|
bool,
|
||||||
|
>(
|
||||||
|
collator_session_keys(),
|
||||||
|
1000,
|
||||||
|
Box::new(|call| RuntimeCall::System(call).encode()),
|
||||||
|
|| (AllowMultiAssetPools::key().to_vec(), AllowMultiAssetPools::get()),
|
||||||
|
|old_value| !old_value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn change_liquidity_withdrawal_fee_by_governance_works() {
|
||||||
|
asset_test_utils::test_cases::change_storage_constant_by_governance_works::<
|
||||||
|
Runtime,
|
||||||
|
LiquidityWithdrawalFee,
|
||||||
|
Permill,
|
||||||
|
>(
|
||||||
|
collator_session_keys(),
|
||||||
|
1000,
|
||||||
|
Box::new(|call| RuntimeCall::System(call).encode()),
|
||||||
|
|| (LiquidityWithdrawalFee::key().to_vec(), LiquidityWithdrawalFee::get()),
|
||||||
|
|old_value| {
|
||||||
|
if let Some(new_value) = old_value.checked_add(&Permill::from_percent(2)) {
|
||||||
|
new_value
|
||||||
|
} else {
|
||||||
|
old_value.checked_sub(&Permill::from_percent(2)).unwrap()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ description = "Assets common utilities"
|
|||||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
||||||
scale-info = { version = "2.9.0", default-features = false, features = ["derive"] }
|
scale-info = { version = "2.9.0", default-features = false, features = ["derive"] }
|
||||||
log = { version = "0.4.19", default-features = false }
|
log = { version = "0.4.19", default-features = false }
|
||||||
|
impl-trait-for-tuples = "0.2.2"
|
||||||
|
|
||||||
# Substrate
|
# Substrate
|
||||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||||
|
|||||||
@@ -37,6 +37,19 @@ where
|
|||||||
) -> Result<MultiAsset, FungiblesAccessError>;
|
) -> Result<MultiAsset, FungiblesAccessError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks for `MultiLocation`.
|
||||||
|
pub trait MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>:
|
||||||
|
MatchesFungibles<AssetId, Balance>
|
||||||
|
where
|
||||||
|
AssetId: Clone,
|
||||||
|
Balance: Clone,
|
||||||
|
MatchAssetId: Contains<MultiLocation>,
|
||||||
|
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||||
|
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||||
|
{
|
||||||
|
fn contains(location: &MultiLocation) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
AssetId: Clone,
|
AssetId: Clone,
|
||||||
Balance: Clone,
|
Balance: Clone,
|
||||||
@@ -82,6 +95,38 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
AssetId: Clone,
|
||||||
|
Balance: Clone,
|
||||||
|
MatchAssetId: Contains<MultiLocation>,
|
||||||
|
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||||
|
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||||
|
> MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||||
|
for MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||||
|
{
|
||||||
|
fn contains(location: &MultiLocation) -> bool {
|
||||||
|
MatchAssetId::contains(location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||||
|
impl<
|
||||||
|
AssetId: Clone,
|
||||||
|
Balance: Clone,
|
||||||
|
MatchAssetId: Contains<MultiLocation>,
|
||||||
|
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||||
|
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||||
|
> MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance> for Tuple
|
||||||
|
{
|
||||||
|
fn contains(location: &MultiLocation) -> bool {
|
||||||
|
for_tuples!( #(
|
||||||
|
match Tuple::contains(location) { o @ true => return o, _ => () }
|
||||||
|
)* );
|
||||||
|
log::trace!(target: "xcm::contains", "did not match location: {:?}", &location);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`MultiAsset`]
|
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`MultiAsset`]
|
||||||
pub fn convert<'a, AssetId, Balance, ConvertAssetId, ConvertBalance, Converter>(
|
pub fn convert<'a, AssetId, Balance, ConvertAssetId, ConvertBalance, Converter>(
|
||||||
items: impl Iterator<Item = &'a (AssetId, Balance)>,
|
items: impl Iterator<Item = &'a (AssetId, Balance)>,
|
||||||
|
|||||||
@@ -13,92 +13,81 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::local_and_foreign_assets::fungibles::Inspect;
|
|
||||||
use cumulus_primitives_core::InteriorMultiLocation;
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
pallet_prelude::DispatchError,
|
pallet_prelude::DispatchError,
|
||||||
traits::{
|
traits::{
|
||||||
fungibles::{
|
fungibles::{Balanced, Create, HandleImbalanceDrop, Inspect, Mutate, Unbalanced},
|
||||||
self, Balanced, Create, HandleImbalanceDrop, Mutate as MutateFungible, Unbalanced,
|
tokens::{
|
||||||
|
DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence,
|
||||||
},
|
},
|
||||||
tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence},
|
AccountTouch, Contains, ContainsPair, Get, PalletInfoAccess,
|
||||||
AccountTouch, ContainsPair, Get, PalletInfoAccess,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use pallet_asset_conversion::MultiAssetIdConverter;
|
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
||||||
use parachains_common::{AccountId, AssetIdForTrustBackedAssets};
|
use parachains_common::AccountId;
|
||||||
use sp_runtime::{traits::MaybeEquivalence, DispatchResult};
|
use sp_runtime::{traits::MaybeEquivalence, DispatchResult};
|
||||||
use sp_std::{boxed::Box, marker::PhantomData};
|
use sp_std::{boxed::Box, marker::PhantomData};
|
||||||
use xcm::{latest::MultiLocation, opaque::lts::Junctions::Here};
|
use xcm::latest::MultiLocation;
|
||||||
use xcm_builder::AsPrefixedGeneralIndex;
|
|
||||||
use xcm_executor::traits::JustTry;
|
|
||||||
|
|
||||||
/// Whether the multilocation refers to an asset in the local assets pallet or not,
|
pub struct MultiLocationConverter<NativeAssetLocation: Get<MultiLocation>, MultiLocationMatcher> {
|
||||||
/// and if return the asset id.
|
_phantom: PhantomData<(NativeAssetLocation, MultiLocationMatcher)>,
|
||||||
fn is_local<TrustBackedAssetsPalletLocation: Get<MultiLocation>>(
|
|
||||||
multilocation: MultiLocation,
|
|
||||||
) -> Option<u32> {
|
|
||||||
AsPrefixedGeneralIndex::<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>::convert(&multilocation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MultiLocationConverter<Balances, ParachainLocation: Get<InteriorMultiLocation>> {
|
impl<NativeAssetLocation, MultiLocationMatcher>
|
||||||
_phantom: PhantomData<(Balances, ParachainLocation)>,
|
MultiAssetIdConverter<Box<MultiLocation>, MultiLocation>
|
||||||
}
|
for MultiLocationConverter<NativeAssetLocation, MultiLocationMatcher>
|
||||||
|
|
||||||
impl<Balances, ParachainLocation> MultiAssetIdConverter<Box<MultiLocation>, MultiLocation>
|
|
||||||
for MultiLocationConverter<Balances, ParachainLocation>
|
|
||||||
where
|
where
|
||||||
Balances: PalletInfoAccess,
|
NativeAssetLocation: Get<MultiLocation>,
|
||||||
ParachainLocation: Get<InteriorMultiLocation>,
|
MultiLocationMatcher: Contains<MultiLocation>,
|
||||||
{
|
{
|
||||||
fn get_native() -> Box<MultiLocation> {
|
fn get_native() -> Box<MultiLocation> {
|
||||||
Box::new(MultiLocation { parents: 0, interior: Here })
|
Box::new(NativeAssetLocation::get())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_native(asset_id: &Box<MultiLocation>) -> bool {
|
fn is_native(asset_id: &Box<MultiLocation>) -> bool {
|
||||||
let mut asset_id = asset_id.clone();
|
*asset_id == Self::get_native()
|
||||||
asset_id.simplify(&ParachainLocation::get());
|
|
||||||
*asset_id == *Self::get_native()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_convert(asset_id: &Box<MultiLocation>) -> Result<MultiLocation, ()> {
|
fn try_convert(
|
||||||
let mut asset_id = asset_id.clone();
|
asset_id: &Box<MultiLocation>,
|
||||||
asset_id.simplify(&ParachainLocation::get());
|
) -> MultiAssetIdConversionResult<Box<MultiLocation>, MultiLocation> {
|
||||||
if Self::is_native(&asset_id) {
|
if Self::is_native(&asset_id) {
|
||||||
// Otherwise it will try and touch the asset to create an account.
|
return MultiAssetIdConversionResult::Native
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
// Return simplified MultiLocation:
|
|
||||||
Ok(*asset_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_multiasset_id(asset_id: &MultiLocation) -> Box<MultiLocation> {
|
if MultiLocationMatcher::contains(&asset_id) {
|
||||||
let mut asset_id = *asset_id;
|
MultiAssetIdConversionResult::Converted(*asset_id.clone())
|
||||||
asset_id.simplify(&ParachainLocation::get());
|
} else {
|
||||||
Box::new(asset_id)
|
MultiAssetIdConversionResult::Unsupported(asset_id.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LocalAndForeignAssets<Assets, ForeignAssets, Location> {
|
pub trait MatchesLocalAndForeignAssetsMultiLocation {
|
||||||
_phantom: PhantomData<(Assets, ForeignAssets, Location)>,
|
fn is_local(location: &MultiLocation) -> bool;
|
||||||
|
fn is_foreign(location: &MultiLocation) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> Unbalanced<AccountId>
|
pub struct LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
_phantom: PhantomData<(Assets, LocalAssetIdConverter, ForeignAssets)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> Unbalanced<AccountId>
|
||||||
|
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
|
||||||
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
|
||||||
+ Unbalanced<AccountId>
|
|
||||||
+ Balanced<AccountId>,
|
|
||||||
Assets: Inspect<AccountId, Balance = u128, AssetId = u32>
|
Assets: Inspect<AccountId, Balance = u128, AssetId = u32>
|
||||||
+ Unbalanced<AccountId>
|
+ Unbalanced<AccountId>
|
||||||
+ Balanced<AccountId>
|
+ Balanced<AccountId>
|
||||||
+ PalletInfoAccess,
|
+ PalletInfoAccess,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
|
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
||||||
|
+ Unbalanced<AccountId>
|
||||||
|
+ Balanced<AccountId>,
|
||||||
{
|
{
|
||||||
fn handle_dust(dust: frame_support::traits::fungibles::Dust<AccountId, Self>) {
|
fn handle_dust(dust: frame_support::traits::fungibles::Dust<AccountId, Self>) {
|
||||||
let credit = dust.into_credit();
|
let credit = dust.into_credit();
|
||||||
|
|
||||||
if let Some(asset) = is_local::<Location>(credit.asset()) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&credit.asset()) {
|
||||||
Assets::handle_raw_dust(asset, credit.peek());
|
Assets::handle_raw_dust(asset, credit.peek());
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::handle_raw_dust(credit.asset(), credit.peek());
|
ForeignAssets::handle_raw_dust(credit.asset(), credit.peek());
|
||||||
@@ -109,14 +98,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_balance(
|
fn write_balance(
|
||||||
asset: <Self as frame_support::traits::fungibles::Inspect<AccountId>>::AssetId,
|
asset: <Self as Inspect<AccountId>>::AssetId,
|
||||||
who: &AccountId,
|
who: &AccountId,
|
||||||
amount: <Self as frame_support::traits::fungibles::Inspect<AccountId>>::Balance,
|
amount: <Self as Inspect<AccountId>>::Balance,
|
||||||
) -> Result<
|
) -> Result<Option<<Self as Inspect<AccountId>>::Balance>, DispatchError> {
|
||||||
Option<<Self as frame_support::traits::fungibles::Inspect<AccountId>>::Balance>,
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
sp_runtime::DispatchError,
|
|
||||||
> {
|
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
|
||||||
Assets::write_balance(asset, who, amount)
|
Assets::write_balance(asset, who, amount)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::write_balance(asset, who, amount)
|
ForeignAssets::write_balance(asset, who, amount)
|
||||||
@@ -125,27 +111,55 @@ where
|
|||||||
|
|
||||||
/// Set the total issuance of `asset` to `amount`.
|
/// Set the total issuance of `asset` to `amount`.
|
||||||
fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) {
|
fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::set_total_issuance(asset, amount)
|
Assets::set_total_issuance(asset, amount)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::set_total_issuance(asset, amount)
|
ForeignAssets::set_total_issuance(asset, amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decrease_balance(
|
||||||
|
asset: Self::AssetId,
|
||||||
|
who: &AccountId,
|
||||||
|
amount: Self::Balance,
|
||||||
|
precision: Precision,
|
||||||
|
preservation: Preservation,
|
||||||
|
force: Fortitude,
|
||||||
|
) -> Result<Self::Balance, DispatchError> {
|
||||||
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
|
Assets::decrease_balance(asset, who, amount, precision, preservation, force)
|
||||||
|
} else {
|
||||||
|
ForeignAssets::decrease_balance(asset, who, amount, precision, preservation, force)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> Inspect<AccountId>
|
fn increase_balance(
|
||||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
asset: Self::AssetId,
|
||||||
|
who: &AccountId,
|
||||||
|
amount: Self::Balance,
|
||||||
|
precision: Precision,
|
||||||
|
) -> Result<Self::Balance, DispatchError> {
|
||||||
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
|
Assets::increase_balance(asset, who, amount, precision)
|
||||||
|
} else {
|
||||||
|
ForeignAssets::increase_balance(asset, who, amount, precision)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> Inspect<AccountId>
|
||||||
|
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
|
||||||
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
|
||||||
Assets: Inspect<AccountId, Balance = u128, AssetId = u32>,
|
Assets: Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
|
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||||
{
|
{
|
||||||
type AssetId = MultiLocation;
|
type AssetId = MultiLocation;
|
||||||
type Balance = u128;
|
type Balance = u128;
|
||||||
|
|
||||||
/// The total amount of issuance in the system.
|
/// The total amount of issuance in the system.
|
||||||
fn total_issuance(asset: Self::AssetId) -> Self::Balance {
|
fn total_issuance(asset: Self::AssetId) -> Self::Balance {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::total_issuance(asset)
|
Assets::total_issuance(asset)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::total_issuance(asset)
|
ForeignAssets::total_issuance(asset)
|
||||||
@@ -154,16 +168,27 @@ where
|
|||||||
|
|
||||||
/// The minimum balance any single account may have.
|
/// The minimum balance any single account may have.
|
||||||
fn minimum_balance(asset: Self::AssetId) -> Self::Balance {
|
fn minimum_balance(asset: Self::AssetId) -> Self::Balance {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::minimum_balance(asset)
|
Assets::minimum_balance(asset)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::minimum_balance(asset)
|
ForeignAssets::minimum_balance(asset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn total_balance(
|
||||||
|
asset: <Self as Inspect<AccountId>>::AssetId,
|
||||||
|
account: &AccountId,
|
||||||
|
) -> <Self as Inspect<AccountId>>::Balance {
|
||||||
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
|
Assets::total_balance(asset, account)
|
||||||
|
} else {
|
||||||
|
ForeignAssets::total_balance(asset, account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the `asset` balance of `who`.
|
/// Get the `asset` balance of `who`.
|
||||||
fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
|
fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::balance(asset, who)
|
Assets::balance(asset, who)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::balance(asset, who)
|
ForeignAssets::balance(asset, who)
|
||||||
@@ -177,7 +202,7 @@ where
|
|||||||
presevation: Preservation,
|
presevation: Preservation,
|
||||||
fortitude: Fortitude,
|
fortitude: Fortitude,
|
||||||
) -> Self::Balance {
|
) -> Self::Balance {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::reducible_balance(asset, who, presevation, fortitude)
|
Assets::reducible_balance(asset, who, presevation, fortitude)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::reducible_balance(asset, who, presevation, fortitude)
|
ForeignAssets::reducible_balance(asset, who, presevation, fortitude)
|
||||||
@@ -196,7 +221,7 @@ where
|
|||||||
amount: Self::Balance,
|
amount: Self::Balance,
|
||||||
mint: Provenance,
|
mint: Provenance,
|
||||||
) -> DepositConsequence {
|
) -> DepositConsequence {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::can_deposit(asset, who, amount, mint)
|
Assets::can_deposit(asset, who, amount, mint)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::can_deposit(asset, who, amount, mint)
|
ForeignAssets::can_deposit(asset, who, amount, mint)
|
||||||
@@ -210,7 +235,7 @@ where
|
|||||||
who: &AccountId,
|
who: &AccountId,
|
||||||
amount: Self::Balance,
|
amount: Self::Balance,
|
||||||
) -> WithdrawConsequence<Self::Balance> {
|
) -> WithdrawConsequence<Self::Balance> {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::can_withdraw(asset, who, amount)
|
Assets::can_withdraw(asset, who, amount)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::can_withdraw(asset, who, amount)
|
ForeignAssets::can_withdraw(asset, who, amount)
|
||||||
@@ -219,36 +244,25 @@ where
|
|||||||
|
|
||||||
/// Returns `true` if an `asset` exists.
|
/// Returns `true` if an `asset` exists.
|
||||||
fn asset_exists(asset: Self::AssetId) -> bool {
|
fn asset_exists(asset: Self::AssetId) -> bool {
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::asset_exists(asset)
|
Assets::asset_exists(asset)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::asset_exists(asset)
|
ForeignAssets::asset_exists(asset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn total_balance(
|
|
||||||
asset: <Self as frame_support::traits::fungibles::Inspect<AccountId>>::AssetId,
|
|
||||||
account: &AccountId,
|
|
||||||
) -> <Self as frame_support::traits::fungibles::Inspect<AccountId>>::Balance {
|
|
||||||
if let Some(asset) = is_local::<Location>(asset) {
|
|
||||||
Assets::total_balance(asset, account)
|
|
||||||
} else {
|
|
||||||
ForeignAssets::total_balance(asset, account)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> MutateFungible<AccountId>
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> Mutate<AccountId>
|
||||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
Assets: Mutate<AccountId>
|
||||||
ForeignAssets: MutateFungible<AccountId, Balance = u128>
|
|
||||||
+ Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
|
||||||
+ Balanced<AccountId>,
|
|
||||||
Assets: MutateFungible<AccountId>
|
|
||||||
+ Inspect<AccountId, Balance = u128, AssetId = u32>
|
+ Inspect<AccountId, Balance = u128, AssetId = u32>
|
||||||
+ Balanced<AccountId>
|
+ Balanced<AccountId>
|
||||||
+ PalletInfoAccess,
|
+ PalletInfoAccess,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
|
ForeignAssets: Mutate<AccountId, Balance = u128>
|
||||||
|
+ Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
||||||
|
+ Balanced<AccountId>,
|
||||||
{
|
{
|
||||||
/// Transfer funds from one account into another.
|
/// Transfer funds from one account into another.
|
||||||
fn transfer(
|
fn transfer(
|
||||||
@@ -258,7 +272,7 @@ where
|
|||||||
amount: Self::Balance,
|
amount: Self::Balance,
|
||||||
keep_alive: Preservation,
|
keep_alive: Preservation,
|
||||||
) -> Result<Self::Balance, DispatchError> {
|
) -> Result<Self::Balance, DispatchError> {
|
||||||
if let Some(asset_id) = is_local::<Location>(asset) {
|
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::transfer(asset_id, source, dest, amount, keep_alive)
|
Assets::transfer(asset_id, source, dest, amount, keep_alive)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::transfer(asset, source, dest, amount, keep_alive)
|
ForeignAssets::transfer(asset, source, dest, amount, keep_alive)
|
||||||
@@ -266,12 +280,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> Create<AccountId>
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> Create<AccountId>
|
||||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
|
||||||
ForeignAssets: Create<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
|
||||||
Assets: Create<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
Assets: Create<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
|
ForeignAssets: Create<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||||
{
|
{
|
||||||
/// Create a new fungible asset.
|
/// Create a new fungible asset.
|
||||||
fn create(
|
fn create(
|
||||||
@@ -280,7 +294,7 @@ where
|
|||||||
is_sufficient: bool,
|
is_sufficient: bool,
|
||||||
min_balance: Self::Balance,
|
min_balance: Self::Balance,
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
if let Some(asset_id) = is_local::<Location>(asset_id) {
|
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||||
Assets::create(asset_id, admin, is_sufficient, min_balance)
|
Assets::create(asset_id, admin, is_sufficient, min_balance)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::create(asset_id, admin, is_sufficient, min_balance)
|
ForeignAssets::create(asset_id, admin, is_sufficient, min_balance)
|
||||||
@@ -288,19 +302,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> AccountTouch<MultiLocation, AccountId>
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> AccountTouch<MultiLocation, AccountId>
|
||||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
|
||||||
ForeignAssets: AccountTouch<MultiLocation, AccountId, Balance = u128>,
|
|
||||||
Assets: AccountTouch<u32, AccountId, Balance = u128>,
|
Assets: AccountTouch<u32, AccountId, Balance = u128>,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
|
ForeignAssets: AccountTouch<MultiLocation, AccountId, Balance = u128>,
|
||||||
{
|
{
|
||||||
type Balance = u128;
|
type Balance = u128;
|
||||||
|
|
||||||
fn deposit_required(
|
fn deposit_required(
|
||||||
asset_id: MultiLocation,
|
asset_id: MultiLocation,
|
||||||
) -> <Self as AccountTouch<MultiLocation, AccountId>>::Balance {
|
) -> <Self as AccountTouch<MultiLocation, AccountId>>::Balance {
|
||||||
if let Some(asset_id) = is_local::<Location>(asset_id) {
|
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||||
Assets::deposit_required(asset_id)
|
Assets::deposit_required(asset_id)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::deposit_required(asset_id)
|
ForeignAssets::deposit_required(asset_id)
|
||||||
@@ -311,8 +325,8 @@ where
|
|||||||
asset_id: MultiLocation,
|
asset_id: MultiLocation,
|
||||||
who: AccountId,
|
who: AccountId,
|
||||||
depositor: AccountId,
|
depositor: AccountId,
|
||||||
) -> Result<(), sp_runtime::DispatchError> {
|
) -> Result<(), DispatchError> {
|
||||||
if let Some(asset_id) = is_local::<Location>(asset_id) {
|
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||||
Assets::touch(asset_id, who, depositor)
|
Assets::touch(asset_id, who, depositor)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::touch(asset_id, who, depositor)
|
ForeignAssets::touch(asset_id, who, depositor)
|
||||||
@@ -321,16 +335,16 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implements [`ContainsPair`] trait for a pair of asset and account IDs.
|
/// Implements [`ContainsPair`] trait for a pair of asset and account IDs.
|
||||||
impl<Assets, ForeignAssets, Location> ContainsPair<MultiLocation, AccountId>
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> ContainsPair<MultiLocation, AccountId>
|
||||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
|
||||||
ForeignAssets: ContainsPair<MultiLocation, AccountId>,
|
|
||||||
Assets: PalletInfoAccess + ContainsPair<u32, AccountId>,
|
Assets: PalletInfoAccess + ContainsPair<u32, AccountId>,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
|
ForeignAssets: ContainsPair<MultiLocation, AccountId>,
|
||||||
{
|
{
|
||||||
/// Check if an account with the given asset ID and account address exists.
|
/// Check if an account with the given asset ID and account address exists.
|
||||||
fn contains(asset_id: &MultiLocation, who: &AccountId) -> bool {
|
fn contains(asset_id: &MultiLocation, who: &AccountId) -> bool {
|
||||||
if let Some(asset_id) = is_local::<Location>(*asset_id) {
|
if let Some(asset_id) = LocalAssetIdConverter::convert(asset_id) {
|
||||||
Assets::contains(&asset_id, &who)
|
Assets::contains(&asset_id, &who)
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::contains(&asset_id, &who)
|
ForeignAssets::contains(&asset_id, &who)
|
||||||
@@ -338,33 +352,33 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> Balanced<AccountId>
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> Balanced<AccountId>
|
||||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
|
||||||
ForeignAssets:
|
|
||||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
|
||||||
Assets:
|
Assets:
|
||||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32> + PalletInfoAccess,
|
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32> + PalletInfoAccess,
|
||||||
{
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
type OnDropDebt = DebtDropIndirection<Assets, ForeignAssets, Location>;
|
|
||||||
type OnDropCredit = CreditDropIndirection<Assets, ForeignAssets, Location>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DebtDropIndirection<Assets, ForeignAssets, Location> {
|
|
||||||
_phantom: PhantomData<LocalAndForeignAssets<Assets, ForeignAssets, Location>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> HandleImbalanceDrop<MultiLocation, u128>
|
|
||||||
for DebtDropIndirection<Assets, ForeignAssets, Location>
|
|
||||||
where
|
|
||||||
Location: Get<MultiLocation>,
|
|
||||||
ForeignAssets:
|
ForeignAssets:
|
||||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||||
|
{
|
||||||
|
type OnDropDebt = DebtDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>;
|
||||||
|
type OnDropCredit = CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DebtDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||||
|
_phantom: PhantomData<LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> HandleImbalanceDrop<MultiLocation, u128>
|
||||||
|
for DebtDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
|
where
|
||||||
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
|
ForeignAssets:
|
||||||
|
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||||
{
|
{
|
||||||
fn handle(asset: MultiLocation, amount: u128) {
|
fn handle(asset: MultiLocation, amount: u128) {
|
||||||
if let Some(asset_id) = is_local::<Location>(asset) {
|
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::OnDropDebt::handle(asset_id, amount);
|
Assets::OnDropDebt::handle(asset_id, amount);
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::OnDropDebt::handle(asset, amount);
|
ForeignAssets::OnDropDebt::handle(asset, amount);
|
||||||
@@ -372,23 +386,87 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CreditDropIndirection<Assets, ForeignAssets, Location> {
|
pub struct CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||||
_phantom: PhantomData<LocalAndForeignAssets<Assets, ForeignAssets, Location>>,
|
_phantom: PhantomData<LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Assets, ForeignAssets, Location> HandleImbalanceDrop<MultiLocation, u128>
|
impl<Assets, LocalAssetIdConverter, ForeignAssets> HandleImbalanceDrop<MultiLocation, u128>
|
||||||
for CreditDropIndirection<Assets, ForeignAssets, Location>
|
for CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||||
where
|
where
|
||||||
Location: Get<MultiLocation>,
|
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||||
|
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||||
ForeignAssets:
|
ForeignAssets:
|
||||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||||
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
|
||||||
{
|
{
|
||||||
fn handle(asset: MultiLocation, amount: u128) {
|
fn handle(asset: MultiLocation, amount: u128) {
|
||||||
if let Some(asset_id) = is_local::<Location>(asset) {
|
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) {
|
||||||
Assets::OnDropCredit::handle(asset_id, amount);
|
Assets::OnDropCredit::handle(asset_id, amount);
|
||||||
} else {
|
} else {
|
||||||
ForeignAssets::OnDropCredit::handle(asset, amount);
|
ForeignAssets::OnDropCredit::handle(asset, amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
local_and_foreign_assets::MultiLocationConverter, matching::StartsWith,
|
||||||
|
AssetIdForPoolAssetsConvert, AssetIdForTrustBackedAssetsConvert,
|
||||||
|
};
|
||||||
|
use frame_support::traits::EverythingBut;
|
||||||
|
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
||||||
|
use sp_runtime::traits::MaybeEquivalence;
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multi_location_converter_works() {
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
pub const WestendLocation: MultiLocation = MultiLocation::parent();
|
||||||
|
pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(50_u8).into();
|
||||||
|
pub PoolAssetsPalletLocation: MultiLocation = PalletInstance(55_u8).into();
|
||||||
|
}
|
||||||
|
|
||||||
|
type C = MultiLocationConverter<
|
||||||
|
WestendLocation,
|
||||||
|
EverythingBut<StartsWith<PoolAssetsPalletLocation>>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
let native_asset = WestendLocation::get();
|
||||||
|
let local_asset =
|
||||||
|
AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::convert_back(
|
||||||
|
&123,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let pool_asset =
|
||||||
|
AssetIdForPoolAssetsConvert::<PoolAssetsPalletLocation>::convert_back(&456).unwrap();
|
||||||
|
let foreign_asset1 = MultiLocation { parents: 1, interior: X1(Parachain(2222)) };
|
||||||
|
let foreign_asset2 = MultiLocation {
|
||||||
|
parents: 2,
|
||||||
|
interior: X2(GlobalConsensus(ByGenesis([1; 32])), Parachain(2222)),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(C::is_native(&Box::new(native_asset)));
|
||||||
|
assert!(!C::is_native(&Box::new(local_asset)));
|
||||||
|
assert!(!C::is_native(&Box::new(pool_asset)));
|
||||||
|
assert!(!C::is_native(&Box::new(foreign_asset1)));
|
||||||
|
assert!(!C::is_native(&Box::new(foreign_asset2)));
|
||||||
|
|
||||||
|
assert_eq!(C::try_convert(&Box::new(native_asset)), MultiAssetIdConversionResult::Native);
|
||||||
|
assert_eq!(
|
||||||
|
C::try_convert(&Box::new(local_asset)),
|
||||||
|
MultiAssetIdConversionResult::Converted(local_asset)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
C::try_convert(&Box::new(pool_asset)),
|
||||||
|
MultiAssetIdConversionResult::Unsupported(Box::new(pool_asset))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
C::try_convert(&Box::new(foreign_asset1)),
|
||||||
|
MultiAssetIdConversionResult::Converted(foreign_asset1)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
C::try_convert(&Box::new(foreign_asset2)),
|
||||||
|
MultiAssetIdConversionResult::Converted(foreign_asset2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ use sp_runtime::{
|
|||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
use xcm_executor::{traits::ConvertLocation, XcmExecutor};
|
use xcm_executor::{traits::ConvertLocation, XcmExecutor};
|
||||||
|
|
||||||
|
// Re-export test_case from `parachains-runtimes-test-utils`
|
||||||
|
pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;
|
||||||
|
|
||||||
/// Test-case makes sure that `Runtime` can receive native asset from relay chain
|
/// Test-case makes sure that `Runtime` can receive native asset from relay chain
|
||||||
/// and can teleport it back and to the other parachains
|
/// and can teleport it back and to the other parachains
|
||||||
pub fn teleports_for_native_asset_works<
|
pub fn teleports_for_native_asset_works<
|
||||||
|
|||||||
@@ -688,6 +688,7 @@ impl_runtime_apis! {
|
|||||||
MultiAsset { fun: Fungible(UNITS), id: Concrete(KsmRelayLocation::get()) },
|
MultiAsset { fun: Fungible(UNITS), id: Concrete(KsmRelayLocation::get()) },
|
||||||
));
|
));
|
||||||
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
||||||
|
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||||
@@ -695,6 +696,7 @@ impl_runtime_apis! {
|
|||||||
|
|
||||||
type CheckedAccount = CheckedAccount;
|
type CheckedAccount = CheckedAccount;
|
||||||
type TrustedTeleporter = TrustedTeleporter;
|
type TrustedTeleporter = TrustedTeleporter;
|
||||||
|
type TrustedReserve = TrustedReserve;
|
||||||
|
|
||||||
fn get_multi_asset() -> MultiAsset {
|
fn get_multi_asset() -> MultiAsset {
|
||||||
MultiAsset {
|
MultiAsset {
|
||||||
|
|||||||
@@ -688,6 +688,7 @@ impl_runtime_apis! {
|
|||||||
MultiAsset { fun: Fungible(UNITS), id: Concrete(DotRelayLocation::get()) },
|
MultiAsset { fun: Fungible(UNITS), id: Concrete(DotRelayLocation::get()) },
|
||||||
));
|
));
|
||||||
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
||||||
|
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||||
@@ -695,6 +696,7 @@ impl_runtime_apis! {
|
|||||||
|
|
||||||
type CheckedAccount = CheckedAccount;
|
type CheckedAccount = CheckedAccount;
|
||||||
type TrustedTeleporter = TrustedTeleporter;
|
type TrustedTeleporter = TrustedTeleporter;
|
||||||
|
type TrustedReserve = TrustedReserve;
|
||||||
|
|
||||||
fn get_multi_asset() -> MultiAsset {
|
fn get_multi_asset() -> MultiAsset {
|
||||||
MultiAsset {
|
MultiAsset {
|
||||||
|
|||||||
@@ -956,6 +956,7 @@ impl_runtime_apis! {
|
|||||||
MultiAsset { fun: Fungible(UNITS), id: Concrete(RelayLocation::get()) },
|
MultiAsset { fun: Fungible(UNITS), id: Concrete(RelayLocation::get()) },
|
||||||
));
|
));
|
||||||
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
|
||||||
|
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||||
@@ -963,6 +964,7 @@ impl_runtime_apis! {
|
|||||||
|
|
||||||
type CheckedAccount = CheckedAccount;
|
type CheckedAccount = CheckedAccount;
|
||||||
type TrustedTeleporter = TrustedTeleporter;
|
type TrustedTeleporter = TrustedTeleporter;
|
||||||
|
type TrustedReserve = TrustedReserve;
|
||||||
|
|
||||||
fn get_multi_asset() -> MultiAsset {
|
fn get_multi_asset() -> MultiAsset {
|
||||||
MultiAsset {
|
MultiAsset {
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ use xcm_executor::XcmExecutor;
|
|||||||
// Re-export test_case from assets
|
// Re-export test_case from assets
|
||||||
pub use asset_test_utils::include_teleports_for_native_asset_works;
|
pub use asset_test_utils::include_teleports_for_native_asset_works;
|
||||||
|
|
||||||
|
// Re-export test_case from `parachains-runtimes-test-utils`
|
||||||
|
pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;
|
||||||
|
|
||||||
/// Test-case makes sure that `Runtime` can process bridging initialize via governance-like call
|
/// Test-case makes sure that `Runtime` can process bridging initialize via governance-like call
|
||||||
pub fn initialize_bridge_by_governance_works<Runtime, GrandpaPalletInstance>(
|
pub fn initialize_bridge_by_governance_works<Runtime, GrandpaPalletInstance>(
|
||||||
collator_session_key: CollatorSessionKeys<Runtime>,
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
@@ -114,76 +117,6 @@ pub fn initialize_bridge_by_governance_works<Runtime, GrandpaPalletInstance>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test-case makes sure that `Runtime` can change storage constant via governance-like call
|
|
||||||
pub fn change_storage_constant_by_governance_works<Runtime, StorageConstant, StorageConstantType>(
|
|
||||||
collator_session_key: CollatorSessionKeys<Runtime>,
|
|
||||||
runtime_para_id: u32,
|
|
||||||
runtime_call_encode: Box<dyn Fn(frame_system::Call<Runtime>) -> Vec<u8>>,
|
|
||||||
storage_constant_key_value: fn() -> (Vec<u8>, StorageConstantType),
|
|
||||||
new_storage_constant_value: fn(&StorageConstantType) -> StorageConstantType,
|
|
||||||
) where
|
|
||||||
Runtime: frame_system::Config
|
|
||||||
+ pallet_balances::Config
|
|
||||||
+ pallet_session::Config
|
|
||||||
+ pallet_xcm::Config
|
|
||||||
+ parachain_info::Config
|
|
||||||
+ pallet_collator_selection::Config
|
|
||||||
+ cumulus_pallet_dmp_queue::Config
|
|
||||||
+ cumulus_pallet_parachain_system::Config,
|
|
||||||
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
|
||||||
StorageConstant: Get<StorageConstantType>,
|
|
||||||
StorageConstantType: Encode + PartialEq + std::fmt::Debug,
|
|
||||||
{
|
|
||||||
ExtBuilder::<Runtime>::default()
|
|
||||||
.with_collators(collator_session_key.collators())
|
|
||||||
.with_session_keys(collator_session_key.session_keys())
|
|
||||||
.with_para_id(runtime_para_id.into())
|
|
||||||
.with_tracing()
|
|
||||||
.build()
|
|
||||||
.execute_with(|| {
|
|
||||||
let (storage_constant_key, storage_constant_init_value): (
|
|
||||||
Vec<u8>,
|
|
||||||
StorageConstantType,
|
|
||||||
) = storage_constant_key_value();
|
|
||||||
|
|
||||||
// check delivery reward constant before (not stored yet, just as default value is used)
|
|
||||||
assert_eq!(StorageConstant::get(), storage_constant_init_value);
|
|
||||||
assert_eq!(sp_io::storage::get(&storage_constant_key), None);
|
|
||||||
|
|
||||||
let new_storage_constant_value =
|
|
||||||
new_storage_constant_value(&storage_constant_init_value);
|
|
||||||
assert_ne!(new_storage_constant_value, storage_constant_init_value);
|
|
||||||
|
|
||||||
// encode `set_storage` call
|
|
||||||
let set_storage_call =
|
|
||||||
runtime_call_encode(frame_system::Call::<Runtime>::set_storage {
|
|
||||||
items: vec![(
|
|
||||||
storage_constant_key.clone(),
|
|
||||||
new_storage_constant_value.encode(),
|
|
||||||
)],
|
|
||||||
});
|
|
||||||
|
|
||||||
// estimate - storing just 1 value
|
|
||||||
use frame_system::WeightInfo;
|
|
||||||
let require_weight_at_most =
|
|
||||||
<Runtime as frame_system::Config>::SystemWeightInfo::set_storage(1);
|
|
||||||
|
|
||||||
// execute XCM with Transact to `set_storage` as governance does
|
|
||||||
assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
|
|
||||||
set_storage_call,
|
|
||||||
require_weight_at_most
|
|
||||||
)
|
|
||||||
.ensure_complete());
|
|
||||||
|
|
||||||
// check delivery reward constant after (stored)
|
|
||||||
assert_eq!(StorageConstant::get(), new_storage_constant_value);
|
|
||||||
assert_eq!(
|
|
||||||
sp_io::storage::get(&storage_constant_key),
|
|
||||||
Some(new_storage_constant_value.encode().into())
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Test-case makes sure that `Runtime` can handle xcm `ExportMessage`:
|
/// Test-case makes sure that `Runtime` can handle xcm `ExportMessage`:
|
||||||
/// Checks if received XCM messages is correctly added to the message outbound queue for delivery.
|
/// Checks if received XCM messages is correctly added to the message outbound queue for delivery.
|
||||||
/// For SystemParachains we expect unpaid execution.
|
/// For SystemParachains we expect unpaid execution.
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ use xcm::{
|
|||||||
};
|
};
|
||||||
use xcm_executor::{traits::TransactAsset, Assets};
|
use xcm_executor::{traits::TransactAsset, Assets};
|
||||||
|
|
||||||
|
pub mod test_cases;
|
||||||
|
|
||||||
pub type BalanceOf<Runtime> = <Runtime as pallet_balances::Config>::Balance;
|
pub type BalanceOf<Runtime> = <Runtime as pallet_balances::Config>::Balance;
|
||||||
pub type AccountIdOf<Runtime> = <Runtime as frame_system::Config>::AccountId;
|
pub type AccountIdOf<Runtime> = <Runtime as frame_system::Config>::AccountId;
|
||||||
pub type ValidatorIdOf<Runtime> = <Runtime as pallet_session::Config>::ValidatorId;
|
pub type ValidatorIdOf<Runtime> = <Runtime as pallet_session::Config>::ValidatorId;
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Cumulus is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Module contains predefined test-case scenarios for `Runtime` with common functionality.
|
||||||
|
|
||||||
|
use crate::{AccountIdOf, CollatorSessionKeys, ExtBuilder, RuntimeHelper, ValidatorIdOf};
|
||||||
|
use codec::Encode;
|
||||||
|
use frame_support::{assert_ok, traits::Get};
|
||||||
|
|
||||||
|
/// Test-case makes sure that `Runtime` can change storage constant via governance-like call
|
||||||
|
pub fn change_storage_constant_by_governance_works<Runtime, StorageConstant, StorageConstantType>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
runtime_call_encode: Box<dyn Fn(frame_system::Call<Runtime>) -> Vec<u8>>,
|
||||||
|
storage_constant_key_value: fn() -> (Vec<u8>, StorageConstantType),
|
||||||
|
new_storage_constant_value: fn(&StorageConstantType) -> StorageConstantType,
|
||||||
|
) where
|
||||||
|
Runtime: frame_system::Config
|
||||||
|
+ pallet_balances::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_xcm::Config
|
||||||
|
+ parachain_info::Config
|
||||||
|
+ pallet_collator_selection::Config
|
||||||
|
+ cumulus_pallet_dmp_queue::Config
|
||||||
|
+ cumulus_pallet_parachain_system::Config,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
StorageConstant: Get<StorageConstantType>,
|
||||||
|
StorageConstantType: Encode + PartialEq + std::fmt::Debug,
|
||||||
|
{
|
||||||
|
ExtBuilder::<Runtime>::default()
|
||||||
|
.with_collators(collator_session_key.collators())
|
||||||
|
.with_session_keys(collator_session_key.session_keys())
|
||||||
|
.with_para_id(runtime_para_id.into())
|
||||||
|
.with_tracing()
|
||||||
|
.build()
|
||||||
|
.execute_with(|| {
|
||||||
|
let (storage_constant_key, storage_constant_init_value): (
|
||||||
|
Vec<u8>,
|
||||||
|
StorageConstantType,
|
||||||
|
) = storage_constant_key_value();
|
||||||
|
|
||||||
|
// check delivery reward constant before (not stored yet, just as default value is used)
|
||||||
|
assert_eq!(StorageConstant::get(), storage_constant_init_value);
|
||||||
|
assert_eq!(sp_io::storage::get(&storage_constant_key), None);
|
||||||
|
|
||||||
|
let new_storage_constant_value =
|
||||||
|
new_storage_constant_value(&storage_constant_init_value);
|
||||||
|
assert_ne!(new_storage_constant_value, storage_constant_init_value);
|
||||||
|
|
||||||
|
// encode `set_storage` call
|
||||||
|
let set_storage_call =
|
||||||
|
runtime_call_encode(frame_system::Call::<Runtime>::set_storage {
|
||||||
|
items: vec![(
|
||||||
|
storage_constant_key.clone(),
|
||||||
|
new_storage_constant_value.encode(),
|
||||||
|
)],
|
||||||
|
});
|
||||||
|
|
||||||
|
// estimate - storing just 1 value
|
||||||
|
use frame_system::WeightInfo;
|
||||||
|
let require_weight_at_most =
|
||||||
|
<Runtime as frame_system::Config>::SystemWeightInfo::set_storage(1);
|
||||||
|
|
||||||
|
// execute XCM with Transact to `set_storage` as governance does
|
||||||
|
assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
|
||||||
|
set_storage_call,
|
||||||
|
require_weight_at_most
|
||||||
|
)
|
||||||
|
.ensure_complete());
|
||||||
|
|
||||||
|
// check delivery reward constant after (stored)
|
||||||
|
assert_eq!(StorageConstant::get(), new_storage_constant_value);
|
||||||
|
assert_eq!(
|
||||||
|
sp_io::storage::get(&storage_constant_key),
|
||||||
|
Some(new_storage_constant_value.encode().into())
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1100,8 +1100,8 @@ pub mod helpers {
|
|||||||
|
|
||||||
pub fn within_threshold(threshold: u64, expected_value: u64, current_value: u64) -> bool {
|
pub fn within_threshold(threshold: u64, expected_value: u64, current_value: u64) -> bool {
|
||||||
let margin = (current_value * threshold) / 100;
|
let margin = (current_value * threshold) / 100;
|
||||||
let lower_limit = expected_value - margin;
|
let lower_limit = expected_value.checked_sub(margin).unwrap_or(u64::MIN);
|
||||||
let upper_limit = expected_value + margin;
|
let upper_limit = expected_value.checked_add(margin).unwrap_or(u64::MAX);
|
||||||
|
|
||||||
current_value >= lower_limit && current_value <= upper_limit
|
current_value >= lower_limit && current_value <= upper_limit
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user