mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-24 14:45:42 +00:00
FRAME: Unity Balance Conversion for Different IDs of Native Asset (#3659)
Introduce types to define 1:1 balance conversion for different relative
asset ids/locations of native asset.
Examples:
native asset on Asset Hub presented as `VersionedLocatableAsset` type in
the context of Relay Chain is
```
{
`location`: (0, Parachain(1000)),
`asset_id`: (1, Here),
}
```
and it's balance should be converted 1:1 by implementations of
`ConversionToAssetBalance` trait.
---------
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
This commit is contained in:
Generated
+35
@@ -820,17 +820,22 @@ dependencies = [
|
|||||||
"assert_matches",
|
"assert_matches",
|
||||||
"asset-hub-rococo-runtime",
|
"asset-hub-rococo-runtime",
|
||||||
"asset-test-utils",
|
"asset-test-utils",
|
||||||
|
"cumulus-pallet-parachain-system",
|
||||||
"emulated-integration-tests-common",
|
"emulated-integration-tests-common",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"pallet-asset-conversion",
|
"pallet-asset-conversion",
|
||||||
"pallet-assets",
|
"pallet-assets",
|
||||||
"pallet-balances",
|
"pallet-balances",
|
||||||
"pallet-message-queue",
|
"pallet-message-queue",
|
||||||
|
"pallet-treasury",
|
||||||
|
"pallet-utility",
|
||||||
"pallet-xcm",
|
"pallet-xcm",
|
||||||
"parachains-common",
|
"parachains-common",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"penpal-runtime",
|
"penpal-runtime",
|
||||||
|
"polkadot-runtime-common",
|
||||||
"rococo-runtime",
|
"rococo-runtime",
|
||||||
|
"rococo-runtime-constants",
|
||||||
"rococo-system-emulated-network",
|
"rococo-system-emulated-network",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"staging-xcm",
|
"staging-xcm",
|
||||||
@@ -2830,6 +2835,36 @@ dependencies = [
|
|||||||
"testnet-parachains-constants",
|
"testnet-parachains-constants",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "collectives-westend-integration-tests"
|
||||||
|
version = "1.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"assert_matches",
|
||||||
|
"asset-hub-westend-runtime",
|
||||||
|
"collectives-westend-runtime",
|
||||||
|
"cumulus-pallet-parachain-system",
|
||||||
|
"cumulus-pallet-xcmp-queue",
|
||||||
|
"emulated-integration-tests-common",
|
||||||
|
"frame-support",
|
||||||
|
"pallet-asset-rate",
|
||||||
|
"pallet-assets",
|
||||||
|
"pallet-balances",
|
||||||
|
"pallet-message-queue",
|
||||||
|
"pallet-treasury",
|
||||||
|
"pallet-utility",
|
||||||
|
"pallet-xcm",
|
||||||
|
"parachains-common",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"polkadot-runtime-common",
|
||||||
|
"sp-runtime",
|
||||||
|
"staging-xcm",
|
||||||
|
"staging-xcm-executor",
|
||||||
|
"testnet-parachains-constants",
|
||||||
|
"westend-runtime",
|
||||||
|
"westend-runtime-constants",
|
||||||
|
"westend-system-emulated-network",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "collectives-westend-runtime"
|
name = "collectives-westend-runtime"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ members = [
|
|||||||
"cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend",
|
"cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend",
|
||||||
"cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo",
|
"cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo",
|
||||||
"cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend",
|
"cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend",
|
||||||
|
"cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend",
|
||||||
"cumulus/parachains/integration-tests/emulated/tests/people/people-rococo",
|
"cumulus/parachains/integration-tests/emulated/tests/people/people-rococo",
|
||||||
"cumulus/parachains/integration-tests/emulated/tests/people/people-westend",
|
"cumulus/parachains/integration-tests/emulated/tests/people/people-westend",
|
||||||
"cumulus/parachains/pallets/collective-content",
|
"cumulus/parachains/pallets/collective-content",
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ decl_test_relay_chains! {
|
|||||||
Hrmp: rococo_runtime::Hrmp,
|
Hrmp: rococo_runtime::Hrmp,
|
||||||
Identity: rococo_runtime::Identity,
|
Identity: rococo_runtime::Identity,
|
||||||
IdentityMigrator: rococo_runtime::IdentityMigrator,
|
IdentityMigrator: rococo_runtime::IdentityMigrator,
|
||||||
|
Treasury: rococo_runtime::Treasury,
|
||||||
|
AssetRate: rococo_runtime::AssetRate,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,15 +21,20 @@ pallet-balances = { path = "../../../../../../../substrate/frame/balances", defa
|
|||||||
pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false }
|
pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false }
|
||||||
pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false }
|
pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false }
|
||||||
pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false }
|
pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false }
|
||||||
|
pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false }
|
||||||
|
pallet-utility = { path = "../../../../../../../substrate/frame/utility", default-features = false }
|
||||||
|
|
||||||
# Polkadot
|
# Polkadot
|
||||||
xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false }
|
xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false }
|
||||||
pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false }
|
pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false }
|
||||||
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false }
|
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false }
|
||||||
rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" }
|
rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" }
|
||||||
|
polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" }
|
||||||
|
rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants" }
|
||||||
|
|
||||||
# Cumulus
|
# Cumulus
|
||||||
asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
|
asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
|
||||||
|
cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false }
|
||||||
parachains-common = { path = "../../../../../common" }
|
parachains-common = { path = "../../../../../common" }
|
||||||
asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" }
|
asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" }
|
||||||
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
|
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
|
||||||
|
|||||||
+1
@@ -19,3 +19,4 @@ mod send;
|
|||||||
mod set_xcm_versions;
|
mod set_xcm_versions;
|
||||||
mod swap;
|
mod swap;
|
||||||
mod teleport;
|
mod teleport;
|
||||||
|
mod treasury;
|
||||||
|
|||||||
+270
@@ -0,0 +1,270 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::imports::*;
|
||||||
|
use emulated_integration_tests_common::accounts::{ALICE, BOB};
|
||||||
|
use frame_support::{
|
||||||
|
dispatch::RawOrigin,
|
||||||
|
sp_runtime::traits::Dispatchable,
|
||||||
|
traits::{
|
||||||
|
fungible::Inspect,
|
||||||
|
fungibles::{Create, Inspect as FungiblesInspect, Mutate},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use parachains_common::AccountId;
|
||||||
|
use polkadot_runtime_common::impls::VersionedLocatableAsset;
|
||||||
|
use rococo_runtime::OriginCaller;
|
||||||
|
use rococo_runtime_constants::currency::GRAND;
|
||||||
|
use xcm_executor::traits::ConvertLocation;
|
||||||
|
|
||||||
|
// Fund Treasury account on Asset Hub from Treasury account on Relay Chain with ROCs.
|
||||||
|
#[test]
|
||||||
|
fn spend_roc_on_asset_hub() {
|
||||||
|
// initial treasury balance on Asset Hub in ROCs.
|
||||||
|
let treasury_balance = 9_000 * GRAND;
|
||||||
|
// the balance spend on Asset Hub.
|
||||||
|
let treasury_spend_balance = 1_000 * GRAND;
|
||||||
|
|
||||||
|
let init_alice_balance = AssetHubRococo::execute_with(|| {
|
||||||
|
<<AssetHubRococo as AssetHubRococoPallet>::Balances as Inspect<_>>::balance(
|
||||||
|
&AssetHubRococo::account_id_of(ALICE),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Rococo::execute_with(|| {
|
||||||
|
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
|
||||||
|
type RuntimeCall = <Rococo as Chain>::RuntimeCall;
|
||||||
|
type Runtime = <Rococo as Chain>::Runtime;
|
||||||
|
type Balances = <Rococo as RococoPallet>::Balances;
|
||||||
|
type Treasury = <Rococo as RococoPallet>::Treasury;
|
||||||
|
|
||||||
|
// Fund Treasury account on Asset Hub with ROCs.
|
||||||
|
|
||||||
|
let root = <Rococo as Chain>::RuntimeOrigin::root();
|
||||||
|
let treasury_account = Treasury::account_id();
|
||||||
|
|
||||||
|
// Mint assets to Treasury account on Relay Chain.
|
||||||
|
assert_ok!(Balances::force_set_balance(
|
||||||
|
root.clone(),
|
||||||
|
treasury_account.clone().into(),
|
||||||
|
treasury_balance * 2,
|
||||||
|
));
|
||||||
|
|
||||||
|
let native_asset = Location::here();
|
||||||
|
let asset_hub_location: Location = [Parachain(1000)].into();
|
||||||
|
let treasury_location: Location = (Parent, PalletInstance(18)).into();
|
||||||
|
|
||||||
|
let teleport_call = RuntimeCall::Utility(pallet_utility::Call::<Runtime>::dispatch_as {
|
||||||
|
as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))),
|
||||||
|
call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::<Runtime>::teleport_assets {
|
||||||
|
dest: bx!(VersionedLocation::V4(asset_hub_location.clone())),
|
||||||
|
beneficiary: bx!(VersionedLocation::V4(treasury_location)),
|
||||||
|
assets: bx!(VersionedAssets::V4(
|
||||||
|
Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into()
|
||||||
|
)),
|
||||||
|
fee_asset_item: 0,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dispatched from Root to `despatch_as` `Signed(treasury_account)`.
|
||||||
|
assert_ok!(teleport_call.dispatch(root));
|
||||||
|
|
||||||
|
assert_expected_events!(
|
||||||
|
Rococo,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Rococo::execute_with(|| {
|
||||||
|
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
|
||||||
|
type RuntimeCall = <Rococo as Chain>::RuntimeCall;
|
||||||
|
type RuntimeOrigin = <Rococo as Chain>::RuntimeOrigin;
|
||||||
|
type Runtime = <Rococo as Chain>::Runtime;
|
||||||
|
type Treasury = <Rococo as RococoPallet>::Treasury;
|
||||||
|
|
||||||
|
// Fund Alice account from Rococo Treasury account on Asset Hub.
|
||||||
|
|
||||||
|
let treasury_origin: RuntimeOrigin =
|
||||||
|
rococo_runtime::governance::pallet_custom_origins::Origin::Treasurer.into();
|
||||||
|
|
||||||
|
let alice_location: Location =
|
||||||
|
[Junction::AccountId32 { network: None, id: Rococo::account_id_of(ALICE).into() }]
|
||||||
|
.into();
|
||||||
|
let asset_hub_location: Location = [Parachain(1000)].into();
|
||||||
|
let native_asset = Location::parent();
|
||||||
|
|
||||||
|
let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::<Runtime>::spend {
|
||||||
|
asset_kind: bx!(VersionedLocatableAsset::V4 {
|
||||||
|
location: asset_hub_location.clone(),
|
||||||
|
asset_id: native_asset.into(),
|
||||||
|
}),
|
||||||
|
amount: treasury_spend_balance,
|
||||||
|
beneficiary: bx!(VersionedLocation::V4(alice_location)),
|
||||||
|
valid_from: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_ok!(treasury_spend_call.dispatch(treasury_origin));
|
||||||
|
|
||||||
|
// Claim the spend.
|
||||||
|
|
||||||
|
let bob_signed = RuntimeOrigin::signed(Rococo::account_id_of(BOB));
|
||||||
|
assert_ok!(Treasury::payout(bob_signed.clone(), 0));
|
||||||
|
|
||||||
|
assert_expected_events!(
|
||||||
|
Rococo,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {},
|
||||||
|
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
AssetHubRococo::execute_with(|| {
|
||||||
|
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
|
||||||
|
type Balances = <AssetHubRococo as AssetHubRococoPallet>::Balances;
|
||||||
|
|
||||||
|
// Ensure that the funds deposited to Alice account.
|
||||||
|
|
||||||
|
let alice_account = AssetHubRococo::account_id_of(ALICE);
|
||||||
|
assert_eq!(
|
||||||
|
<Balances as Inspect<_>>::balance(&alice_account),
|
||||||
|
treasury_spend_balance + init_alice_balance
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert events triggered by xcm pay program:
|
||||||
|
// 1. treasury asset transferred to spend beneficiary;
|
||||||
|
// 2. response to Relay Chain Treasury pallet instance sent back;
|
||||||
|
// 3. XCM program completed;
|
||||||
|
assert_expected_events!(
|
||||||
|
AssetHubRococo,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {},
|
||||||
|
RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {},
|
||||||
|
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_and_claim_treasury_spend_in_usdt() {
|
||||||
|
const ASSET_ID: u32 = 1984;
|
||||||
|
const SPEND_AMOUNT: u128 = 1_000_000;
|
||||||
|
// treasury location from a sibling parachain.
|
||||||
|
let treasury_location: Location = Location::new(1, PalletInstance(18));
|
||||||
|
// treasury account on a sibling parachain.
|
||||||
|
let treasury_account =
|
||||||
|
asset_hub_rococo_runtime::xcm_config::LocationToAccountId::convert_location(
|
||||||
|
&treasury_location,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let asset_hub_location =
|
||||||
|
v3::Location::new(0, v3::Junction::Parachain(AssetHubRococo::para_id().into()));
|
||||||
|
let root = <Rococo as Chain>::RuntimeOrigin::root();
|
||||||
|
// asset kind to be spend from the treasury.
|
||||||
|
let asset_kind = VersionedLocatableAsset::V3 {
|
||||||
|
location: asset_hub_location,
|
||||||
|
asset_id: v3::AssetId::Concrete(
|
||||||
|
(v3::Junction::PalletInstance(50), v3::Junction::GeneralIndex(ASSET_ID.into())).into(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
// treasury spend beneficiary.
|
||||||
|
let alice: AccountId = Rococo::account_id_of(ALICE);
|
||||||
|
let bob: AccountId = Rococo::account_id_of(BOB);
|
||||||
|
let bob_signed = <Rococo as Chain>::RuntimeOrigin::signed(bob.clone());
|
||||||
|
|
||||||
|
AssetHubRococo::execute_with(|| {
|
||||||
|
type Assets = <AssetHubRococo as AssetHubRococoPallet>::Assets;
|
||||||
|
|
||||||
|
// create an asset class and mint some assets to the treasury account.
|
||||||
|
assert_ok!(<Assets as Create<_>>::create(
|
||||||
|
ASSET_ID,
|
||||||
|
treasury_account.clone(),
|
||||||
|
true,
|
||||||
|
SPEND_AMOUNT / 2
|
||||||
|
));
|
||||||
|
assert_ok!(<Assets as Mutate<_>>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4));
|
||||||
|
// beneficiary has zero balance.
|
||||||
|
assert_eq!(<Assets as FungiblesInspect<_>>::balance(ASSET_ID, &alice,), 0u128,);
|
||||||
|
});
|
||||||
|
|
||||||
|
Rococo::execute_with(|| {
|
||||||
|
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
|
||||||
|
type Treasury = <Rococo as RococoPallet>::Treasury;
|
||||||
|
type AssetRate = <Rococo as RococoPallet>::AssetRate;
|
||||||
|
|
||||||
|
// create a conversion rate from `asset_kind` to the native currency.
|
||||||
|
assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into()));
|
||||||
|
|
||||||
|
// create and approve a treasury spend.
|
||||||
|
assert_ok!(Treasury::spend(
|
||||||
|
root,
|
||||||
|
Box::new(asset_kind),
|
||||||
|
SPEND_AMOUNT,
|
||||||
|
Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
// claim the spend.
|
||||||
|
assert_ok!(Treasury::payout(bob_signed.clone(), 0));
|
||||||
|
|
||||||
|
assert_expected_events!(
|
||||||
|
Rococo,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
AssetHubRococo::execute_with(|| {
|
||||||
|
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
|
||||||
|
type Assets = <AssetHubRococo as AssetHubRococoPallet>::Assets;
|
||||||
|
|
||||||
|
// assert events triggered by xcm pay program
|
||||||
|
// 1. treasury asset transferred to spend beneficiary
|
||||||
|
// 2. response to Relay Chain treasury pallet instance sent back
|
||||||
|
// 3. XCM program completed
|
||||||
|
assert_expected_events!(
|
||||||
|
AssetHubRococo,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => {
|
||||||
|
id: id == &ASSET_ID,
|
||||||
|
from: from == &treasury_account,
|
||||||
|
to: to == &alice,
|
||||||
|
amount: amount == &SPEND_AMOUNT,
|
||||||
|
},
|
||||||
|
RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {},
|
||||||
|
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
// beneficiary received the assets from the treasury.
|
||||||
|
assert_eq!(<Assets as FungiblesInspect<_>>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,);
|
||||||
|
});
|
||||||
|
|
||||||
|
Rococo::execute_with(|| {
|
||||||
|
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
|
||||||
|
type Treasury = <Rococo as RococoPallet>::Treasury;
|
||||||
|
|
||||||
|
// check the payment status to ensure the response from the AssetHub was received.
|
||||||
|
assert_ok!(Treasury::check_status(bob_signed, 0));
|
||||||
|
assert_expected_events!(
|
||||||
|
Rococo,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
[package]
|
||||||
|
name = "collectives-westend-integration-tests"
|
||||||
|
version = "1.0.0"
|
||||||
|
authors.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
license = "Apache-2.0"
|
||||||
|
description = "Collectives Westend runtime integration tests with xcm-emulator"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false }
|
||||||
|
assert_matches = "1.5.0"
|
||||||
|
|
||||||
|
# Substrate
|
||||||
|
sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false }
|
||||||
|
frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false }
|
||||||
|
pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false }
|
||||||
|
pallet-asset-rate = { path = "../../../../../../../substrate/frame/asset-rate", default-features = false }
|
||||||
|
pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false }
|
||||||
|
pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false }
|
||||||
|
pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false }
|
||||||
|
pallet-utility = { path = "../../../../../../../substrate/frame/utility", default-features = false }
|
||||||
|
|
||||||
|
# Polkadot
|
||||||
|
polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" }
|
||||||
|
xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false }
|
||||||
|
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false }
|
||||||
|
pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false }
|
||||||
|
westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" }
|
||||||
|
westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants" }
|
||||||
|
|
||||||
|
# Cumulus
|
||||||
|
parachains-common = { path = "../../../../../../parachains/common" }
|
||||||
|
testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["westend"] }
|
||||||
|
asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" }
|
||||||
|
collectives-westend-runtime = { path = "../../../../../runtimes/collectives/collectives-westend" }
|
||||||
|
cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../../pallets/xcmp-queue" }
|
||||||
|
cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" }
|
||||||
|
emulated-integration-tests-common = { path = "../../../common", default-features = false }
|
||||||
|
westend-system-emulated-network = { path = "../../../networks/westend-system" }
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
pub use xcm::{prelude::*, v3};
|
||||||
|
|
||||||
|
pub use emulated_integration_tests_common::xcm_emulator::{
|
||||||
|
assert_expected_events, bx, Chain, RelayChain as Relay, TestExt,
|
||||||
|
};
|
||||||
|
pub use westend_system_emulated_network::{
|
||||||
|
asset_hub_westend_emulated_chain::AssetHubWestendParaPallet as AssetHubWestendPallet,
|
||||||
|
collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet,
|
||||||
|
westend_emulated_chain::WestendRelayPallet as WestendPallet,
|
||||||
|
AssetHubWestendPara as AssetHubWestend, CollectivesWestendPara as CollectivesWestend,
|
||||||
|
WestendRelay as Westend,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
+236
@@ -0,0 +1,236 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::*;
|
||||||
|
use asset_hub_westend_runtime::xcm_config::LocationToAccountId as AssetHubLocationToAccountId;
|
||||||
|
use emulated_integration_tests_common::accounts::ALICE;
|
||||||
|
use frame_support::{
|
||||||
|
assert_ok, dispatch::RawOrigin, instances::Instance1, sp_runtime::traits::Dispatchable,
|
||||||
|
traits::fungible::Inspect,
|
||||||
|
};
|
||||||
|
use polkadot_runtime_common::impls::VersionedLocatableAsset;
|
||||||
|
use westend_runtime::OriginCaller;
|
||||||
|
use westend_runtime_constants::currency::UNITS;
|
||||||
|
use xcm_executor::traits::ConvertLocation;
|
||||||
|
|
||||||
|
// Fund Fellowship Treasury from Westend Treasury and spend from Fellowship Treasury.
|
||||||
|
#[test]
|
||||||
|
fn fellowship_treasury_spend() {
|
||||||
|
// initial treasury balance on Asset Hub in WNDs.
|
||||||
|
let treasury_balance = 20_000_000 * UNITS;
|
||||||
|
// target fellowship balance on Asset Hub in WNDs.
|
||||||
|
let fellowship_treasury_balance = 1_000_000 * UNITS;
|
||||||
|
// fellowship first spend balance in WNDs.
|
||||||
|
let fellowship_spend_balance = 10_000 * UNITS;
|
||||||
|
|
||||||
|
let init_alice_balance = AssetHubWestend::execute_with(|| {
|
||||||
|
<<AssetHubWestend as AssetHubWestendPallet>::Balances as Inspect<_>>::balance(
|
||||||
|
&AssetHubWestend::account_id_of(ALICE),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Westend::execute_with(|| {
|
||||||
|
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
|
||||||
|
type RuntimeCall = <Westend as Chain>::RuntimeCall;
|
||||||
|
type Runtime = <Westend as Chain>::Runtime;
|
||||||
|
type Balances = <Westend as WestendPallet>::Balances;
|
||||||
|
type Treasury = <Westend as WestendPallet>::Treasury;
|
||||||
|
|
||||||
|
// Fund Treasury account on Asset Hub with WNDs.
|
||||||
|
|
||||||
|
let root = <Westend as Chain>::RuntimeOrigin::root();
|
||||||
|
let treasury_account = Treasury::account_id();
|
||||||
|
|
||||||
|
// Mist assets to Treasury account on Relay Chain.
|
||||||
|
assert_ok!(Balances::force_set_balance(
|
||||||
|
root.clone(),
|
||||||
|
treasury_account.clone().into(),
|
||||||
|
treasury_balance * 2,
|
||||||
|
));
|
||||||
|
|
||||||
|
let native_asset = Location::here();
|
||||||
|
let asset_hub_location: Location = [Parachain(1000)].into();
|
||||||
|
let treasury_location: Location = (Parent, PalletInstance(37)).into();
|
||||||
|
|
||||||
|
let teleport_call = RuntimeCall::Utility(pallet_utility::Call::<Runtime>::dispatch_as {
|
||||||
|
as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))),
|
||||||
|
call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::<Runtime>::teleport_assets {
|
||||||
|
dest: bx!(VersionedLocation::V4(asset_hub_location.clone())),
|
||||||
|
beneficiary: bx!(VersionedLocation::V4(treasury_location)),
|
||||||
|
assets: bx!(VersionedAssets::V4(
|
||||||
|
Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into()
|
||||||
|
)),
|
||||||
|
fee_asset_item: 0,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dispatched from Root to `dispatch_as` `Signed(treasury_account)`.
|
||||||
|
assert_ok!(teleport_call.dispatch(root));
|
||||||
|
|
||||||
|
assert_expected_events!(
|
||||||
|
Westend,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Westend::execute_with(|| {
|
||||||
|
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
|
||||||
|
type RuntimeCall = <Westend as Chain>::RuntimeCall;
|
||||||
|
type RuntimeOrigin = <Westend as Chain>::RuntimeOrigin;
|
||||||
|
type Runtime = <Westend as Chain>::Runtime;
|
||||||
|
type Treasury = <Westend as WestendPallet>::Treasury;
|
||||||
|
|
||||||
|
// Fund Fellowship Treasury from Westend Treasury.
|
||||||
|
|
||||||
|
let treasury_origin: RuntimeOrigin =
|
||||||
|
westend_runtime::governance::pallet_custom_origins::Origin::Treasurer.into();
|
||||||
|
let fellowship_treasury_location: Location =
|
||||||
|
Location::new(1, [Parachain(1001), PalletInstance(65)]);
|
||||||
|
let asset_hub_location: Location = [Parachain(1000)].into();
|
||||||
|
let native_asset = Location::parent();
|
||||||
|
|
||||||
|
let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::<Runtime>::spend {
|
||||||
|
asset_kind: bx!(VersionedLocatableAsset::V4 {
|
||||||
|
location: asset_hub_location.clone(),
|
||||||
|
asset_id: native_asset.into(),
|
||||||
|
}),
|
||||||
|
amount: fellowship_treasury_balance,
|
||||||
|
beneficiary: bx!(VersionedLocation::V4(fellowship_treasury_location)),
|
||||||
|
valid_from: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_ok!(treasury_spend_call.dispatch(treasury_origin));
|
||||||
|
|
||||||
|
// Claim the spend.
|
||||||
|
|
||||||
|
let alice_signed = RuntimeOrigin::signed(Westend::account_id_of(ALICE));
|
||||||
|
assert_ok!(Treasury::payout(alice_signed.clone(), 0));
|
||||||
|
|
||||||
|
assert_expected_events!(
|
||||||
|
Westend,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {},
|
||||||
|
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
AssetHubWestend::execute_with(|| {
|
||||||
|
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
|
||||||
|
type Balances = <AssetHubWestend as AssetHubWestendPallet>::Balances;
|
||||||
|
|
||||||
|
// Ensure that the funds deposited to the Fellowship Treasury account.
|
||||||
|
|
||||||
|
let fellowship_treasury_location: Location =
|
||||||
|
Location::new(1, [Parachain(1001), PalletInstance(65)]);
|
||||||
|
let fellowship_treasury_account =
|
||||||
|
AssetHubLocationToAccountId::convert_location(&fellowship_treasury_location).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
<Balances as Inspect<_>>::balance(&fellowship_treasury_account),
|
||||||
|
fellowship_treasury_balance
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert events triggered by xcm pay program:
|
||||||
|
// 1. treasury asset transferred to spend beneficiary;
|
||||||
|
// 2. response to Relay Chain Treasury pallet instance sent back;
|
||||||
|
// 3. XCM program completed;
|
||||||
|
assert_expected_events!(
|
||||||
|
AssetHubWestend,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {},
|
||||||
|
RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {},
|
||||||
|
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
CollectivesWestend::execute_with(|| {
|
||||||
|
type RuntimeEvent = <CollectivesWestend as Chain>::RuntimeEvent;
|
||||||
|
type RuntimeCall = <CollectivesWestend as Chain>::RuntimeCall;
|
||||||
|
type RuntimeOrigin = <CollectivesWestend as Chain>::RuntimeOrigin;
|
||||||
|
type Runtime = <CollectivesWestend as Chain>::Runtime;
|
||||||
|
type FellowshipTreasury =
|
||||||
|
<CollectivesWestend as CollectivesWestendPallet>::FellowshipTreasury;
|
||||||
|
|
||||||
|
// Fund Alice account from Fellowship Treasury.
|
||||||
|
|
||||||
|
let fellows_origin: RuntimeOrigin =
|
||||||
|
collectives_westend_runtime::fellowship::pallet_fellowship_origins::Origin::Fellows
|
||||||
|
.into();
|
||||||
|
let asset_hub_location: Location = (Parent, Parachain(1000)).into();
|
||||||
|
let native_asset = Location::parent();
|
||||||
|
|
||||||
|
let alice_location: Location = [Junction::AccountId32 {
|
||||||
|
network: None,
|
||||||
|
id: CollectivesWestend::account_id_of(ALICE).into(),
|
||||||
|
}]
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let fellowship_treasury_spend_call =
|
||||||
|
RuntimeCall::FellowshipTreasury(pallet_treasury::Call::<Runtime, Instance1>::spend {
|
||||||
|
asset_kind: bx!(VersionedLocatableAsset::V4 {
|
||||||
|
location: asset_hub_location,
|
||||||
|
asset_id: native_asset.into(),
|
||||||
|
}),
|
||||||
|
amount: fellowship_spend_balance,
|
||||||
|
beneficiary: bx!(VersionedLocation::V4(alice_location)),
|
||||||
|
valid_from: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_ok!(fellowship_treasury_spend_call.dispatch(fellows_origin));
|
||||||
|
|
||||||
|
// Claim the spend.
|
||||||
|
|
||||||
|
let alice_signed = RuntimeOrigin::signed(CollectivesWestend::account_id_of(ALICE));
|
||||||
|
assert_ok!(FellowshipTreasury::payout(alice_signed.clone(), 0));
|
||||||
|
|
||||||
|
assert_expected_events!(
|
||||||
|
CollectivesWestend,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {},
|
||||||
|
RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::Paid { .. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
AssetHubWestend::execute_with(|| {
|
||||||
|
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
|
||||||
|
type Balances = <AssetHubWestend as AssetHubWestendPallet>::Balances;
|
||||||
|
|
||||||
|
// Ensure that the funds deposited to Alice account.
|
||||||
|
|
||||||
|
let alice_account = AssetHubWestend::account_id_of(ALICE);
|
||||||
|
assert_eq!(
|
||||||
|
<Balances as Inspect<_>>::balance(&alice_account),
|
||||||
|
fellowship_spend_balance + init_alice_balance
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert events triggered by xcm pay program:
|
||||||
|
// 1. treasury asset transferred to spend beneficiary;
|
||||||
|
// 2. response to Relay Chain Treasury pallet instance sent back;
|
||||||
|
// 3. XCM program completed;
|
||||||
|
assert_expected_events!(
|
||||||
|
AssetHubWestend,
|
||||||
|
vec![
|
||||||
|
RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {},
|
||||||
|
RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
|
||||||
|
RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
mod fellowship_treasury;
|
||||||
@@ -21,13 +21,16 @@ mod tracks;
|
|||||||
use crate::{
|
use crate::{
|
||||||
weights,
|
weights,
|
||||||
xcm_config::{FellowshipAdminBodyId, LocationToAccountId, TreasurerBodyId, UsdtAssetHub},
|
xcm_config::{FellowshipAdminBodyId, LocationToAccountId, TreasurerBodyId, UsdtAssetHub},
|
||||||
AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage,
|
AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation,
|
||||||
Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS,
|
ParachainInfo, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler,
|
||||||
|
WestendTreasuryAccount, DAYS,
|
||||||
};
|
};
|
||||||
|
use cumulus_primitives_core::ParaId;
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
parameter_types,
|
parameter_types,
|
||||||
traits::{
|
traits::{
|
||||||
EitherOf, EitherOfDiverse, MapSuccess, NeverEnsureOrigin, OriginTrait, TryWithMorphedArg,
|
tokens::UnityOrOuterConversion, EitherOf, EitherOfDiverse, FromContains, MapSuccess,
|
||||||
|
NeverEnsureOrigin, OriginTrait, TryWithMorphedArg,
|
||||||
},
|
},
|
||||||
PalletId,
|
PalletId,
|
||||||
};
|
};
|
||||||
@@ -40,10 +43,10 @@ use pallet_ranked_collective::EnsureOfRank;
|
|||||||
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
|
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
|
||||||
use parachains_common::impls::ToParentTreasury;
|
use parachains_common::impls::ToParentTreasury;
|
||||||
use polkadot_runtime_common::impls::{
|
use polkadot_runtime_common::impls::{
|
||||||
LocatableAssetConverter, VersionedLocatableAsset, VersionedLocationConverter,
|
ContainsParts, LocatableAssetConverter, VersionedLocatableAsset, VersionedLocationConverter,
|
||||||
};
|
};
|
||||||
use sp_arithmetic::Permill;
|
use sp_arithmetic::Permill;
|
||||||
use sp_core::{ConstU128, ConstU32};
|
use sp_core::{ConstU128, ConstU32, ConstU8};
|
||||||
use sp_runtime::traits::{ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst};
|
use sp_runtime::traits::{ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst};
|
||||||
use testnet_parachains_constants::westend::{account, currency::GRAND};
|
use testnet_parachains_constants::westend::{account, currency::GRAND};
|
||||||
use westend_runtime_constants::time::HOURS;
|
use westend_runtime_constants::time::HOURS;
|
||||||
@@ -263,6 +266,7 @@ parameter_types! {
|
|||||||
// The asset's interior location for the paying account. This is the Fellowship Treasury
|
// The asset's interior location for the paying account. This is the Fellowship Treasury
|
||||||
// pallet instance (which sits at index 65).
|
// pallet instance (which sits at index 65).
|
||||||
pub FellowshipTreasuryInteriorLocation: InteriorLocation = PalletInstance(65).into();
|
pub FellowshipTreasuryInteriorLocation: InteriorLocation = PalletInstance(65).into();
|
||||||
|
pub SelfParaId: ParaId = ParachainInfo::parachain_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
@@ -345,7 +349,15 @@ impl pallet_treasury::Config<FellowshipTreasuryInstance> for Runtime {
|
|||||||
type Paymaster = FellowshipTreasuryPaymaster;
|
type Paymaster = FellowshipTreasuryPaymaster;
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
type Paymaster = PayWithEnsure<FellowshipTreasuryPaymaster, OpenHrmpChannel<ConstU32<1000>>>;
|
type Paymaster = PayWithEnsure<FellowshipTreasuryPaymaster, OpenHrmpChannel<ConstU32<1000>>>;
|
||||||
type BalanceConverter = AssetRate;
|
type BalanceConverter = UnityOrOuterConversion<
|
||||||
|
ContainsParts<
|
||||||
|
FromContains<
|
||||||
|
xcm_builder::IsSiblingSystemParachain<ParaId, SelfParaId>,
|
||||||
|
xcm_builder::IsParentsOnly<ConstU8<1>>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
AssetRate,
|
||||||
|
>;
|
||||||
type PayoutPeriod = ConstU32<{ 30 * DAYS }>;
|
type PayoutPeriod = ConstU32<{ 30 * DAYS }>;
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments<
|
type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments<
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
use frame_support::traits::{
|
use frame_support::traits::{
|
||||||
fungible::{Balanced, Credit},
|
fungible::{Balanced, Credit},
|
||||||
tokens::imbalance::ResolveTo,
|
tokens::imbalance::ResolveTo,
|
||||||
Imbalance, OnUnbalanced,
|
Contains, ContainsPair, Imbalance, OnUnbalanced,
|
||||||
};
|
};
|
||||||
use pallet_treasury::TreasuryAccountId;
|
use pallet_treasury::TreasuryAccountId;
|
||||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||||
@@ -156,6 +156,26 @@ impl TryConvert<&VersionedLocation, xcm::latest::Location> for VersionedLocation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adapter for [`Contains`] trait to match [`VersionedLocatableAsset`] type converted to the latest
|
||||||
|
/// version of itself where it's location matched by `L` and it's asset id by `A` parameter types.
|
||||||
|
pub struct ContainsParts<C>(core::marker::PhantomData<C>);
|
||||||
|
impl<C> Contains<VersionedLocatableAsset> for ContainsParts<C>
|
||||||
|
where
|
||||||
|
C: ContainsPair<xcm::latest::Location, xcm::latest::Location>,
|
||||||
|
{
|
||||||
|
fn contains(asset: &VersionedLocatableAsset) -> bool {
|
||||||
|
use VersionedLocatableAsset::*;
|
||||||
|
let (location, asset_id) = match asset.clone() {
|
||||||
|
V3 { location, asset_id } => match (location.try_into(), asset_id.try_into()) {
|
||||||
|
(Ok(l), Ok(a)) => (l, a),
|
||||||
|
_ => return false,
|
||||||
|
},
|
||||||
|
V4 { location, asset_id } => (location, asset_id),
|
||||||
|
};
|
||||||
|
C::contains(&location, &asset_id.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
pub mod benchmarks {
|
pub mod benchmarks {
|
||||||
use super::VersionedLocatableAsset;
|
use super::VersionedLocatableAsset;
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ use beefy_primitives::{
|
|||||||
ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature},
|
ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature},
|
||||||
mmr::{BeefyDataProvider, MmrLeafVersion},
|
mmr::{BeefyDataProvider, MmrLeafVersion},
|
||||||
};
|
};
|
||||||
use frame_support::dynamic_params::{dynamic_pallet_params, dynamic_params};
|
use frame_support::{
|
||||||
|
dynamic_params::{dynamic_pallet_params, dynamic_params},
|
||||||
|
traits::FromContains,
|
||||||
|
};
|
||||||
use pallet_nis::WithMaximumOf;
|
use pallet_nis::WithMaximumOf;
|
||||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||||
use primitives::{
|
use primitives::{
|
||||||
@@ -40,7 +43,8 @@ use rococo_runtime_constants::system_parachain::BROKER_ID;
|
|||||||
use runtime_common::{
|
use runtime_common::{
|
||||||
assigned_slots, auctions, claims, crowdloan, identity_migrator, impl_runtime_weights,
|
assigned_slots, auctions, claims, crowdloan, identity_migrator, impl_runtime_weights,
|
||||||
impls::{
|
impls::{
|
||||||
LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter,
|
ContainsParts, LocatableAssetConverter, ToAuthor, VersionedLocatableAsset,
|
||||||
|
VersionedLocationConverter,
|
||||||
},
|
},
|
||||||
paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
|
paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
|
||||||
traits::{Leaser, OnSwap},
|
traits::{Leaser, OnSwap},
|
||||||
@@ -74,10 +78,10 @@ use frame_support::{
|
|||||||
genesis_builder_helper::{build_state, get_preset},
|
genesis_builder_helper::{build_state, get_preset},
|
||||||
parameter_types,
|
parameter_types,
|
||||||
traits::{
|
traits::{
|
||||||
fungible::HoldConsideration, Contains, EitherOf, EitherOfDiverse, EnsureOrigin,
|
fungible::HoldConsideration, tokens::UnityOrOuterConversion, Contains, EitherOf,
|
||||||
EnsureOriginWithArg, EverythingBut, InstanceFilter, KeyOwnerProofSystem,
|
EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg, EverythingBut, InstanceFilter,
|
||||||
LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim,
|
KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError,
|
||||||
WithdrawReasons,
|
StorageMapShim, WithdrawReasons,
|
||||||
},
|
},
|
||||||
weights::{ConstantMultiplier, WeightMeter, WeightToFee as _},
|
weights::{ConstantMultiplier, WeightMeter, WeightToFee as _},
|
||||||
PalletId,
|
PalletId,
|
||||||
@@ -87,7 +91,7 @@ use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId};
|
|||||||
use pallet_identity::legacy::IdentityInfo;
|
use pallet_identity::legacy::IdentityInfo;
|
||||||
use pallet_session::historical as session_historical;
|
use pallet_session::historical as session_historical;
|
||||||
use pallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo};
|
use pallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo};
|
||||||
use sp_core::{ConstU128, OpaqueMetadata, H256};
|
use sp_core::{ConstU128, ConstU8, OpaqueMetadata, H256};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys,
|
create_runtime_str, generic, impl_opaque_keys,
|
||||||
traits::{
|
traits::{
|
||||||
@@ -523,7 +527,15 @@ impl pallet_treasury::Config for Runtime {
|
|||||||
LocatableAssetConverter,
|
LocatableAssetConverter,
|
||||||
VersionedLocationConverter,
|
VersionedLocationConverter,
|
||||||
>;
|
>;
|
||||||
type BalanceConverter = AssetRate;
|
type BalanceConverter = UnityOrOuterConversion<
|
||||||
|
ContainsParts<
|
||||||
|
FromContains<
|
||||||
|
xcm_builder::IsChildSystemParachain<ParaId>,
|
||||||
|
xcm_builder::IsParentsOnly<ConstU8<1>>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
AssetRate,
|
||||||
|
>;
|
||||||
type PayoutPeriod = PayoutSpendPeriod;
|
type PayoutPeriod = PayoutSpendPeriod;
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments;
|
type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments;
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ use frame_support::{
|
|||||||
genesis_builder_helper::{build_state, get_preset},
|
genesis_builder_helper::{build_state, get_preset},
|
||||||
parameter_types,
|
parameter_types,
|
||||||
traits::{
|
traits::{
|
||||||
fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut,
|
fungible::HoldConsideration, tokens::UnityOrOuterConversion, ConstU32, Contains, EitherOf,
|
||||||
InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage,
|
EitherOfDiverse, EverythingBut, FromContains, InstanceFilter, KeyOwnerProofSystem,
|
||||||
ProcessMessageError, WithdrawReasons,
|
LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons,
|
||||||
},
|
},
|
||||||
weights::{ConstantMultiplier, WeightMeter, WeightToFee as _},
|
weights::{ConstantMultiplier, WeightMeter, WeightToFee as _},
|
||||||
PalletId,
|
PalletId,
|
||||||
@@ -57,7 +57,8 @@ use runtime_common::{
|
|||||||
elections::OnChainAccuracy,
|
elections::OnChainAccuracy,
|
||||||
identity_migrator, impl_runtime_weights,
|
identity_migrator, impl_runtime_weights,
|
||||||
impls::{
|
impls::{
|
||||||
LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter,
|
ContainsParts, LocatableAssetConverter, ToAuthor, VersionedLocatableAsset,
|
||||||
|
VersionedLocationConverter,
|
||||||
},
|
},
|
||||||
paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
|
paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
|
||||||
traits::{Leaser, OnSwap},
|
traits::{Leaser, OnSwap},
|
||||||
@@ -80,7 +81,7 @@ use runtime_parachains::{
|
|||||||
shared as parachains_shared,
|
shared as parachains_shared,
|
||||||
};
|
};
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
use sp_core::{OpaqueMetadata, RuntimeDebug, H256};
|
use sp_core::{ConstU8, OpaqueMetadata, RuntimeDebug, H256};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
create_runtime_str,
|
create_runtime_str,
|
||||||
curve::PiecewiseLinear,
|
curve::PiecewiseLinear,
|
||||||
@@ -712,7 +713,15 @@ impl pallet_treasury::Config for Runtime {
|
|||||||
LocatableAssetConverter,
|
LocatableAssetConverter,
|
||||||
VersionedLocationConverter,
|
VersionedLocationConverter,
|
||||||
>;
|
>;
|
||||||
type BalanceConverter = AssetRate;
|
type BalanceConverter = UnityOrOuterConversion<
|
||||||
|
ContainsParts<
|
||||||
|
FromContains<
|
||||||
|
xcm_builder::IsChildSystemParachain<ParaId>,
|
||||||
|
xcm_builder::IsParentsOnly<ConstU8<1>>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
AssetRate,
|
||||||
|
>;
|
||||||
type PayoutPeriod = PayoutSpendPeriod;
|
type PayoutPeriod = PayoutSpendPeriod;
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments;
|
type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments;
|
||||||
|
|||||||
@@ -322,6 +322,29 @@ impl<ParaId: IsSystem + From<u32>> Contains<Location> for IsChildSystemParachain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Matches if the given location is a system-level sibling parachain.
|
||||||
|
pub struct IsSiblingSystemParachain<ParaId, SelfParaId>(PhantomData<(ParaId, SelfParaId)>);
|
||||||
|
impl<ParaId: IsSystem + From<u32> + Eq, SelfParaId: Get<ParaId>> Contains<Location>
|
||||||
|
for IsSiblingSystemParachain<ParaId, SelfParaId>
|
||||||
|
{
|
||||||
|
fn contains(l: &Location) -> bool {
|
||||||
|
matches!(
|
||||||
|
l.unpack(),
|
||||||
|
(1, [Junction::Parachain(id)])
|
||||||
|
if SelfParaId::get() != ParaId::from(*id) && ParaId::from(*id).is_system(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Matches if the given location contains only the specified amount of parents and no interior
|
||||||
|
/// junctions.
|
||||||
|
pub struct IsParentsOnly<Count>(PhantomData<Count>);
|
||||||
|
impl<Count: Get<u8>> Contains<Location> for IsParentsOnly<Count> {
|
||||||
|
fn contains(t: &Location) -> bool {
|
||||||
|
t.contains_parents_only(Count::get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Allows only messages if the generic `ResponseHandler` expects them via `expecting_response`.
|
/// Allows only messages if the generic `ResponseHandler` expects them via `expecting_response`.
|
||||||
pub struct AllowKnownQueryResponses<ResponseHandler>(PhantomData<ResponseHandler>);
|
pub struct AllowKnownQueryResponses<ResponseHandler>(PhantomData<ResponseHandler>);
|
||||||
impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<ResponseHandler> {
|
impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<ResponseHandler> {
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ mod barriers;
|
|||||||
pub use barriers::{
|
pub use barriers::{
|
||||||
AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||||
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain,
|
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain,
|
||||||
DenyThenTry, IsChildSystemParachain, RespectSuspension, TakeWeightCredit, TrailingSetTopicAsId,
|
DenyThenTry, IsChildSystemParachain, IsParentsOnly, IsSiblingSystemParachain,
|
||||||
WithComputedOrigin,
|
RespectSuspension, TakeWeightCredit, TrailingSetTopicAsId, WithComputedOrigin,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod controller;
|
mod controller;
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
|
||||||
|
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
|
||||||
|
|
||||||
|
title: Unity Balance Conversion for Different IDs of Native Asset
|
||||||
|
|
||||||
|
doc:
|
||||||
|
- audience: Runtime Dev
|
||||||
|
description: |
|
||||||
|
Introduce types to define 1:1 balance conversion for different relative asset ids/locations
|
||||||
|
of native asset for `ConversionToAssetBalance` trait bounds.
|
||||||
|
|
||||||
|
crates: [ ]
|
||||||
@@ -36,7 +36,7 @@ mod members;
|
|||||||
pub use members::{AllowAll, DenyAll, Filter};
|
pub use members::{AllowAll, DenyAll, Filter};
|
||||||
pub use members::{
|
pub use members::{
|
||||||
AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Equals, Everything,
|
AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Equals, Everything,
|
||||||
EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing,
|
EverythingBut, FromContains, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing,
|
||||||
RankedMembers, RankedMembersSwapHandler, SortedMembers, TheseExcept,
|
RankedMembers, RankedMembersSwapHandler, SortedMembers, TheseExcept,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,15 @@ impl<A, B, CP: ContainsPair<A, B>> Contains<(A, B)> for FromContainsPair<CP> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [`ContainsPair`] implementation that has a `Contains` implementation for each member of the
|
||||||
|
/// pair.
|
||||||
|
pub struct FromContains<CA, CB>(PhantomData<(CA, CB)>);
|
||||||
|
impl<A, B, CA: Contains<A>, CB: Contains<B>> ContainsPair<A, B> for FromContains<CA, CB> {
|
||||||
|
fn contains(a: &A, b: &B) -> bool {
|
||||||
|
CA::contains(a) && CB::contains(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`Contains`] implementation that contains every value.
|
/// A [`Contains`] implementation that contains every value.
|
||||||
pub enum Everything {}
|
pub enum Everything {}
|
||||||
impl<T> Contains<T> for Everything {
|
impl<T> Contains<T> for Everything {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub mod pay;
|
|||||||
pub use misc::{
|
pub use misc::{
|
||||||
AssetId, Balance, BalanceStatus, ConversionFromAssetBalance, ConversionToAssetBalance,
|
AssetId, Balance, BalanceStatus, ConversionFromAssetBalance, ConversionToAssetBalance,
|
||||||
ConvertRank, DepositConsequence, ExistenceRequirement, Fortitude, GetSalary, Locker, Precision,
|
ConvertRank, DepositConsequence, ExistenceRequirement, Fortitude, GetSalary, Locker, Precision,
|
||||||
Preservation, Provenance, Restriction, UnityAssetBalanceConversion, WithdrawConsequence,
|
Preservation, Provenance, Restriction, UnityAssetBalanceConversion, UnityOrOuterConversion,
|
||||||
WithdrawReasons,
|
WithdrawConsequence, WithdrawReasons,
|
||||||
};
|
};
|
||||||
pub use pay::{Pay, PayFromAccount, PaymentStatus};
|
pub use pay::{Pay, PayFromAccount, PaymentStatus};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
//! Miscellaneous types.
|
//! Miscellaneous types.
|
||||||
|
|
||||||
|
use crate::traits::Contains;
|
||||||
use codec::{Decode, Encode, FullCodec, MaxEncodedLen};
|
use codec::{Decode, Encode, FullCodec, MaxEncodedLen};
|
||||||
use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero};
|
use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero};
|
||||||
use sp_core::RuntimeDebug;
|
use sp_core::RuntimeDebug;
|
||||||
@@ -299,6 +300,33 @@ where
|
|||||||
fn ensure_successful(_: AssetId) {}
|
fn ensure_successful(_: AssetId) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implements [`ConversionFromAssetBalance`], allowing for a 1:1 balance conversion of the asset
|
||||||
|
/// when it meets the conditions specified by `C`. If the conditions are not met, the conversion is
|
||||||
|
/// delegated to `O`.
|
||||||
|
pub struct UnityOrOuterConversion<C, O>(core::marker::PhantomData<(C, O)>);
|
||||||
|
impl<AssetBalance, AssetId, OutBalance, C, O>
|
||||||
|
ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance> for UnityOrOuterConversion<C, O>
|
||||||
|
where
|
||||||
|
C: Contains<AssetId>,
|
||||||
|
O: ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance>,
|
||||||
|
AssetBalance: Into<OutBalance>,
|
||||||
|
{
|
||||||
|
type Error = O::Error;
|
||||||
|
fn from_asset_balance(
|
||||||
|
balance: AssetBalance,
|
||||||
|
asset_id: AssetId,
|
||||||
|
) -> Result<OutBalance, Self::Error> {
|
||||||
|
if C::contains(&asset_id) {
|
||||||
|
return Ok(balance.into());
|
||||||
|
}
|
||||||
|
O::from_asset_balance(balance, asset_id)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
fn ensure_successful(asset_id: AssetId) {
|
||||||
|
O::ensure_successful(asset_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait to handle NFT locking mechanism to ensure interactions with the asset can be implemented
|
/// Trait to handle NFT locking mechanism to ensure interactions with the asset can be implemented
|
||||||
/// downstream to extend logic of Uniques/Nfts current functionality.
|
/// downstream to extend logic of Uniques/Nfts current functionality.
|
||||||
pub trait Locker<CollectionId, ItemId> {
|
pub trait Locker<CollectionId, ItemId> {
|
||||||
|
|||||||
Reference in New Issue
Block a user