From da40d97a2311640fe3f0da486f2ebf4cb840f40f Mon Sep 17 00:00:00 2001 From: Muharem Date: Fri, 8 Dec 2023 14:02:09 +0100 Subject: [PATCH] Westend: Fellowship Treasury (#2532) Treasury Pallet Instance for the Fellowship in Westend Collectives. In this update, we present a Treasury Pallet Instance that is under the control of the Fellowship body, with oversight from the Root and Treasurer origins. Here's how it is governed: - the Root origin have the authority to reject or approve spend proposals, with no amount limit for approvals. - the Treasurer origin have the authority to reject or approve spend proposals, with approval limits of up to 10,000,000 DOT. - Voice of all Fellows ranked at 3 or above can reject or approve spend proposals, with a maximum approval limit of 10,000 DOT. - Voice of Fellows ranked at 4 or above can also reject or approve spend proposals, with a maximum approval limit of 10,000,000 DOT. Additionally, we introduce the Asset Rate Pallet Instance to establish conversion rates from asset A to B. This is used to determine if a proposed spend amount involving a non-native asset is permissible by the commanding origin. The rates can be set up by the Root, Treasurer origins, or Voice of all Fellows. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: joepetrowski --- Cargo.lock | 19 ++ Cargo.toml | 1 + cumulus/parachains/common/src/polkadot.rs | 2 + cumulus/parachains/common/src/westend.rs | 2 + .../collectives-westend/Cargo.toml | 25 ++ .../collectives-westend/src/genesis.rs | 67 ++++++ .../collectives-westend/src/lib.rs | 51 +++++ .../networks/westend-system/Cargo.toml | 1 + .../networks/westend-system/src/lib.rs | 4 + .../tests/assets/asset-hub-westend/Cargo.toml | 1 + .../tests/assets/asset-hub-westend/src/lib.rs | 7 +- .../src/tests/fellowship_treasury.rs | 131 +++++++++++ .../assets/asset-hub-westend/src/tests/mod.rs | 1 + .../asset-hub-westend/src/xcm_config.rs | 16 ++ .../collectives-westend/Cargo.toml | 8 + .../collectives-westend/src/fellowship/mod.rs | 128 ++++++++++- .../collectives-westend/src/lib.rs | 27 ++- .../collectives-westend/src/weights/mod.rs | 2 + .../src/weights/pallet_asset_rate.rs | 85 +++++++ .../src/weights/pallet_treasury.rs | 214 ++++++++++++++++++ .../collectives-westend/src/xcm_config.rs | 6 +- polkadot/runtime/common/src/impls.rs | 21 +- polkadot/runtime/westend/constants/src/lib.rs | 1 + polkadot/runtime/westend/src/xcm_config.rs | 13 +- prdoc/pr_2532.prdoc | 11 + substrate/frame/treasury/src/benchmarking.rs | 10 +- 26 files changed, 827 insertions(+), 27 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs create mode 100644 prdoc/pr_2532.prdoc diff --git a/Cargo.lock b/Cargo.lock index 1dd20a128494..ee8158689577 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -885,6 +885,7 @@ dependencies = [ "asset-test-utils", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", "frame-system", @@ -2613,6 +2614,21 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "collectives-westend-emulated-chain" +version = "0.0.0" +dependencies = [ + "collectives-westend-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "serde_json", + "sp-core", + "sp-runtime", + "westend-emulated-chain", +] + [[package]] name = "collectives-westend-runtime" version = "1.0.0" @@ -2634,6 +2650,7 @@ dependencies = [ "hex-literal", "log", "pallet-alliance", + "pallet-asset-rate", "pallet-aura", "pallet-authorship", "pallet-balances", @@ -2653,6 +2670,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", "pallet-utility", "pallet-xcm", "parachains-common", @@ -21049,6 +21067,7 @@ version = "0.0.0" dependencies = [ "asset-hub-westend-emulated-chain", "bridge-hub-westend-emulated-chain", + "collectives-westend-emulated-chain", "emulated-integration-tests-common", "penpal-emulated-chain", "westend-emulated-chain", diff --git a/Cargo.toml b/Cargo.toml index 26d48ba0ced7..1c791b6118f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,7 @@ members = [ "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend", + "cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal", "cumulus/parachains/integration-tests/emulated/chains/relays/rococo", "cumulus/parachains/integration-tests/emulated/chains/relays/westend", diff --git a/cumulus/parachains/common/src/polkadot.rs b/cumulus/parachains/common/src/polkadot.rs index 744108bce2e5..ca4138303421 100644 --- a/cumulus/parachains/common/src/polkadot.rs +++ b/cumulus/parachains/common/src/polkadot.rs @@ -31,6 +31,8 @@ pub mod account { /// It is used as a temporarily place to deposit a slashed imbalance /// before the teleport to the Treasury. pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); + /// Fellowship treasury pallet ID + pub const FELLOWSHIP_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/feltr"); } /// Consensus-related. diff --git a/cumulus/parachains/common/src/westend.rs b/cumulus/parachains/common/src/westend.rs index 0ae21e234549..2bd4d18a15eb 100644 --- a/cumulus/parachains/common/src/westend.rs +++ b/cumulus/parachains/common/src/westend.rs @@ -29,6 +29,8 @@ pub mod account { /// Ambassador Referenda pallet ID - used as a temporary place to deposit a slashed imbalance /// before the teleport to the Treasury. pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); + /// Fellowship treasury pallet ID. + pub const FELLOWSHIP_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/feltr"); } pub mod currency { diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml new file mode 100644 index 000000000000..5dcf139bdb7b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "collectives-westend-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Collectives Westend emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +collectives-westend-runtime = { path = "../../../../../../runtimes/collectives/collectives-westend" } +westend-emulated-chain = { path = "../../../relays/westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs new file mode 100644 index 000000000000..d79ef55072ae --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs @@ -0,0 +1,67 @@ +// 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. + +// Substrate +use sp_core::storage::Storage; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1001; +pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = collectives_westend_runtime::RuntimeGenesisConfig { + system: collectives_westend_runtime::SystemConfig::default(), + balances: collectives_westend_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: collectives_westend_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: collectives_westend_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: collectives_westend_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + collectives_westend_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: collectives_westend_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage( + &genesis_config, + collectives_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs new file mode 100644 index 000000000000..5d553b6f1034 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs @@ -0,0 +1,51 @@ +// 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 mod genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impls::Parachain, xcm_emulator::decl_test_parachains, +}; + +// CollectivesWestend Parachain declaration +decl_test_parachains! { + pub struct CollectivesWestend { + genesis = genesis::genesis(), + on_init = { + collectives_westend_runtime::AuraExt::on_initialize(1); + }, + runtime = collectives_westend_runtime, + core = { + XcmpMessageHandler: collectives_westend_runtime::XcmpQueue, + LocationToAccountId: collectives_westend_runtime::xcm_config::LocationToAccountId, + ParachainInfo: collectives_westend_runtime::ParachainInfo, + }, + pallets = { + PolkadotXcm: collectives_westend_runtime::PolkadotXcm, + Balances: collectives_westend_runtime::Balances, + FellowshipTreasury: collectives_westend_runtime::FellowshipTreasury, + AssetRate: collectives_westend_runtime::AssetRate, + } + }, +} + +// AssetHubWestend implementation +impl_accounts_helpers_for_parachain!(CollectivesWestend); +impl_assert_events_helpers_for_parachain!(CollectivesWestend); diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml index a4360076d6bd..634111bc3812 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml @@ -13,4 +13,5 @@ emulated-integration-tests-common = { path = "../../common", default-features = westend-emulated-chain = { path = "../../chains/relays/westend", default-features = false } asset-hub-westend-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-westend" } bridge-hub-westend-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-westend" } +collectives-westend-emulated-chain = { path = "../../chains/parachains/collectives/collectives-westend" } penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs index 667b44a69869..26cd5c7e8608 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs @@ -15,11 +15,13 @@ pub use asset_hub_westend_emulated_chain; pub use bridge_hub_westend_emulated_chain; +pub use collectives_westend_emulated_chain; pub use penpal_emulated_chain; pub use westend_emulated_chain; use asset_hub_westend_emulated_chain::AssetHubWestend; use bridge_hub_westend_emulated_chain::BridgeHubWestend; +use collectives_westend_emulated_chain::CollectivesWestend; use penpal_emulated_chain::{PenpalA, PenpalB}; use westend_emulated_chain::Westend; @@ -35,6 +37,7 @@ decl_test_networks! { parachains = vec![ AssetHubWestend, BridgeHubWestend, + CollectivesWestend, PenpalA, PenpalB, ], @@ -46,6 +49,7 @@ decl_test_sender_receiver_accounts_parameter_types! { WestendRelay { sender: ALICE, receiver: BOB }, AssetHubWestendPara { sender: ALICE, receiver: BOB }, BridgeHubWestendPara { sender: ALICE, receiver: BOB }, + CollectivesWestendPara { sender: ALICE, receiver: BOB }, PenpalAPara { sender: ALICE, receiver: BOB }, PenpalBPara { sender: ALICE, receiver: BOB } } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index cdaa65f02cb7..a0861b49955c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -36,6 +36,7 @@ parachains-common = { path = "../../../../../../parachains/common" } asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../../pallets/dmp-queue" } +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" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index e2c03d2f8f0d..e9c7a59faaf6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -47,11 +47,16 @@ pub use westend_system_emulated_network::{ asset_hub_westend_emulated_chain::{ genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, }, + collectives_westend_emulated_chain::{ + genesis::ED as COLLECTIVES_WESTEND_ED, + CollectivesWestendParaPallet as CollectivesWestendPallet, + }, penpal_emulated_chain::PenpalBParaPallet as PenpalBPallet, westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubWestendPara as BridgeHubWestend, - BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, PenpalBPara as PenpalB, + BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, + CollectivesWestendPara as CollectivesWestend, PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender, WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs new file mode 100644 index 000000000000..d7de0a451f20 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs @@ -0,0 +1,131 @@ +// 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 emulated_integration_tests_common::accounts::{ALICE, BOB}; +use frame_support::traits::fungibles::{Create, Inspect, Mutate}; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use xcm_executor::traits::ConvertLocation; + +#[test] +fn create_and_claim_treasury_spend() { + const ASSET_ID: u32 = 1984; + const SPEND_AMOUNT: u128 = 1_000_000; + // treasury location from a sibling parachain. + let treasury_location: MultiLocation = MultiLocation::new( + 1, + X2(Parachain(CollectivesWestend::para_id().into()), PalletInstance(65)), + ); + // treasury account on a sibling parachain. + let treasury_account = + asset_hub_westend_runtime::xcm_config::LocationToAccountId::convert_location( + &treasury_location, + ) + .unwrap(); + let asset_hub_location = MultiLocation::new(1, Parachain(AssetHubWestend::para_id().into())); + let root = ::RuntimeOrigin::root(); + // asset kind to be spent from the treasury. + let asset_kind = VersionedLocatableAsset::V3 { + location: asset_hub_location, + asset_id: AssetId::Concrete((PalletInstance(50), GeneralIndex(ASSET_ID.into())).into()), + }; + // treasury spend beneficiary. + let alice: AccountId = Westend::account_id_of(ALICE); + let bob: AccountId = CollectivesWestend::account_id_of(BOB); + let bob_signed = ::RuntimeOrigin::signed(bob.clone()); + + AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + + // create an asset class and mint some assets to the treasury account. + assert_ok!(>::create( + ASSET_ID, + treasury_account.clone(), + true, + SPEND_AMOUNT / 2 + )); + assert_ok!(>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4)); + // beneficiary has zero balance. + assert_eq!(>::balance(ASSET_ID, &alice,), 0u128,); + }); + + CollectivesWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type FellowshipTreasury = + ::FellowshipTreasury; + type AssetRate = ::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!(FellowshipTreasury::spend( + root, + Box::new(asset_kind), + SPEND_AMOUNT, + Box::new(MultiLocation::new(0, Into::<[u8; 32]>::into(alice.clone())).into()), + None, + )); + // claim the spend. + assert_ok!(FellowshipTreasury::payout(bob_signed.clone(), 0)); + + assert_expected_events!( + CollectivesWestend, + vec![ + RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::Paid { .. }) => {}, + ] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Assets = ::Assets; + + // assert events triggered by xcm pay program + // 1. treasury asset transferred to spend beneficiary + // 2. response to the Fellowship treasury pallet instance sent back + // 3. XCM program completed + assert_expected_events!( + AssetHubWestend, + 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::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, + ] + ); + // beneficiary received the assets from the treasury. + assert_eq!(>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,); + }); + + CollectivesWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type FellowshipTreasury = + ::FellowshipTreasury; + + // check the payment status to ensure the response from the AssetHub was received. + assert_ok!(FellowshipTreasury::check_status(bob_signed, 0)); + assert_expected_events!( + CollectivesWestend, + vec![ + RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index d2127b63048b..ee720c244804 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod fellowship_treasury; mod reserve_transfer; mod send; mod set_xcm_versions; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 19fd9b0b928d..946ab9696f7f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -239,6 +239,18 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; + pub type FellowshipEntities: impl Contains = { + // Fellowship Plurality + MultiLocation { parents: 1, interior: X2(Parachain(1001), Plurality { id: BodyId::Technical, ..}) } | + // Fellowship Salary Pallet + MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(64)) } | + // Fellowship Treasury Pallet + MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(65)) } + }; + pub type AmbassadorEntities: impl Contains = { + // Ambassador Salary Pallet + MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(74)) } + }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -487,6 +499,8 @@ pub type Barrier = TrailingSetTopicAsId< ParentOrParentsPlurality, Equals, Equals, + FellowshipEntities, + AmbassadorEntities, )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, @@ -525,6 +539,8 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = pub type WaivedLocations = ( RelayOrOtherSystemParachains, Equals, + FellowshipEntities, + AmbassadorEntities, ); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 94a5edc371f6..433e55c6ea94 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -21,6 +21,7 @@ frame-system = { path = "../../../../../substrate/frame/system", default-feature frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } +pallet-asset-rate = { path = "../../../../../substrate/frame/asset-rate", default-features = false } pallet-alliance = { path = "../../../../../substrate/frame/alliance", default-features = false } pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } @@ -34,6 +35,7 @@ pallet-session = { path = "../../../../../substrate/frame/session", default-feat pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-treasury = { path = "../../../../../substrate/frame/treasury", default-features = false } pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } pallet-referenda = { path = "../../../../../substrate/frame/referenda", default-features = false } pallet-ranked-collective = { path = "../../../../../substrate/frame/ranked-collective", default-features = false } @@ -97,6 +99,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-alliance/runtime-benchmarks", + "pallet-asset-rate/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-collective-content/runtime-benchmarks", @@ -111,6 +114,7 @@ runtime-benchmarks = [ "pallet-salary/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", @@ -130,6 +134,7 @@ try-runtime = [ "frame-system/try-runtime", "frame-try-runtime/try-runtime", "pallet-alliance/try-runtime", + "pallet-asset-rate/try-runtime", "pallet-aura/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", @@ -148,6 +153,7 @@ try-runtime = [ "pallet-session/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", + "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", @@ -172,6 +178,7 @@ std = [ "frame-try-runtime?/std", "log/std", "pallet-alliance/std", + "pallet-asset-rate/std", "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", @@ -191,6 +198,7 @@ std = [ "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", + "pallet-treasury/std", "pallet-utility/std", "pallet-xcm/std", "parachain-info/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs index b7412705dde7..3fd108c0a5cf 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs @@ -21,28 +21,41 @@ mod tracks; use crate::{ impls::ToParentTreasury, weights, - xcm_config::{FellowshipAdminBodyId, UsdtAssetHub}, - AccountId, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage, Runtime, - RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS, + xcm_config::{FellowshipAdminBodyId, TreasurerBodyId, UsdtAssetHub}, + AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage, + Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS, }; use frame_support::{ parameter_types, - traits::{EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, TryWithMorphedArg}, + traits::{ + EitherOf, EitherOfDiverse, MapSuccess, NeverEnsureOrigin, OriginTrait, TryWithMorphedArg, + }, + PalletId, }; -use frame_system::EnsureRootWithSuccess; +use frame_system::{EnsureRoot, EnsureRootWithSuccess}; pub use origins::{ pallet_origins as pallet_fellowship_origins, Architects, EnsureCanPromoteTo, EnsureCanRetainAt, EnsureFellowship, Fellows, Masters, Members, ToVoice, }; use pallet_ranked_collective::EnsureOfRank; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use parachains_common::{polkadot::account, HOURS}; +use parachains_common::westend::{account, currency::GRAND}; +use polkadot_runtime_common::impls::{ + LocatableAssetConverter, VersionedLocatableAsset, VersionedMultiLocationConverter, +}; +use sp_arithmetic::Permill; use sp_core::{ConstU128, ConstU32}; -use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst}; +use sp_runtime::traits::{ + AccountIdConversion, ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst, +}; +use westend_runtime_constants::time::HOURS; +use xcm::prelude::*; use xcm_builder::{AliasesIntoAccountId32, PayOverXcm}; #[cfg(feature = "runtime-benchmarks")] use crate::impls::benchmarks::{OpenHrmpChannel, PayWithEnsure}; +#[cfg(feature = "runtime-benchmarks")] +use parachains_common::westend::currency::DOLLARS; /// The Fellowship members' ranks. pub mod ranks { @@ -191,8 +204,6 @@ impl pallet_core_fellowship::Config for Runtime { pub type FellowshipSalaryInstance = pallet_salary::Instance1; -use xcm::prelude::*; - parameter_types! { // The interior location on AssetHub for the paying account. This is the Fellowship Salary // pallet instance (which sits at index 64). This sovereign account will need funding. @@ -236,3 +247,102 @@ impl pallet_salary::Config for Runtime { // Total monthly salary budget. type Budget = ConstU128<{ 100_000 * USDT_UNITS }>; } + +parameter_types! { + pub const FellowshipTreasuryPalletId: PalletId = account::FELLOWSHIP_TREASURY_PALLET_ID; + pub const HundredPercent: Permill = Permill::from_percent(100); + pub const Burn: Permill = Permill::from_percent(0); + pub const MaxBalance: Balance = Balance::max_value(); + // The asset's interior location for the paying account. This is the Fellowship Treasury + // pallet instance (which sits at index 65). + pub FellowshipTreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(65).into(); +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + // Benchmark bond. Needed to make `propose_spend` work. + pub const TenPercent: Permill = Permill::from_percent(10); + // Benchmark minimum. Needed to make `propose_spend` work. + pub const BenchmarkProposalBondMinimum: Balance = 1 * DOLLARS; + // Benchmark maximum. Needed to make `propose_spend` work. + pub const BenchmarkProposalBondMaximum: Balance = 10 * DOLLARS; +} + +/// [`PayOverXcm`] setup to pay the Fellowship Treasury. +pub type FellowshipTreasuryPaymaster = PayOverXcm< + FellowshipTreasuryInteriorLocation, + crate::xcm_config::XcmRouter, + crate::PolkadotXcm, + ConstU32<{ 6 * HOURS }>, + VersionedMultiLocation, + VersionedLocatableAsset, + LocatableAssetConverter, + VersionedMultiLocationConverter, +>; + +pub type FellowshipTreasuryInstance = pallet_treasury::Instance1; + +impl pallet_treasury::Config for Runtime { + // The creation of proposals via the treasury pallet is deprecated and should not be utilized. + // Instead, public or fellowship referenda should be used to propose and command the treasury + // spend or spend_local dispatchables. The parameters below have been configured accordingly to + // discourage its use. + // TODO: replace with `NeverEnsure` once polkadot-sdk 1.5 is released. + type ApproveOrigin = NeverEnsureOrigin<()>; + type OnSlash = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type ProposalBond = HundredPercent; + #[cfg(not(feature = "runtime-benchmarks"))] + type ProposalBondMinimum = MaxBalance; + #[cfg(not(feature = "runtime-benchmarks"))] + type ProposalBondMaximum = MaxBalance; + + #[cfg(feature = "runtime-benchmarks")] + type ProposalBond = TenPercent; + #[cfg(feature = "runtime-benchmarks")] + type ProposalBondMinimum = BenchmarkProposalBondMinimum; + #[cfg(feature = "runtime-benchmarks")] + type ProposalBondMaximum = BenchmarkProposalBondMaximum; + // end. + + type WeightInfo = weights::pallet_treasury::WeightInfo; + type PalletId = FellowshipTreasuryPalletId; + type Currency = Balances; + type RejectOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse>, Fellows>, + >; + type RuntimeEvent = RuntimeEvent; + type SpendPeriod = ConstU32<{ 7 * DAYS }>; + type Burn = Burn; + type BurnDestination = (); + type SpendFunds = (); + type MaxApprovals = ConstU32<100>; + type SpendOrigin = EitherOf< + EitherOf< + EnsureRootWithSuccess, + MapSuccess< + EnsureXcm>, + Replace>, + >, + >, + EitherOf< + MapSuccess>>, + MapSuccess>>, + >, + >; + type AssetKind = VersionedLocatableAsset; + type Beneficiary = VersionedMultiLocation; + type BeneficiaryLookup = IdentityLookup; + #[cfg(not(feature = "runtime-benchmarks"))] + type Paymaster = FellowshipTreasuryPaymaster; + #[cfg(feature = "runtime-benchmarks")] + type Paymaster = PayWithEnsure>>; + type BalanceConverter = AssetRate; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments< + sp_core::ConstU8<1>, + ConstU32<1000>, + >; +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 3b8ce0a87045..9135405155b2 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -89,14 +89,16 @@ use parachains_common::{ SLOT_DURATION, }; use sp_runtime::RuntimeDebug; -use xcm_config::{GovernanceLocation, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{GovernanceLocation, TreasurerBodyId, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; +use polkadot_runtime_common::{ + impls::VersionedLocatableAsset, BlockHashCount, SlowAdjustingFeeUpdate, +}; use xcm::latest::{prelude::*, BodyId}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -325,6 +327,7 @@ impl InstanceFilter for ProxyType { RuntimeCall::FellowshipReferenda { .. } | RuntimeCall::FellowshipCore { .. } | RuntimeCall::FellowshipSalary { .. } | + RuntimeCall::FellowshipTreasury { .. } | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -613,6 +616,21 @@ impl pallet_preimage::Config for Runtime { >; } +impl pallet_asset_rate::Config for Runtime { + type WeightInfo = weights::pallet_asset_rate::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type CreateOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse>, Fellows>, + >; + type RemoveOrigin = Self::CreateOrigin; + type UpdateOrigin = Self::CreateOrigin; + type Currency = Balances; + type AssetKind = VersionedLocatableAsset; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::AssetRateArguments; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -648,6 +666,7 @@ construct_runtime!( Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 43, Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 44, + AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event} = 45, // The main stage. @@ -665,6 +684,8 @@ construct_runtime!( FellowshipCore: pallet_core_fellowship::::{Pallet, Call, Storage, Event} = 63, // pub type FellowshipSalaryInstance = pallet_salary::Instance1; FellowshipSalary: pallet_salary::::{Pallet, Call, Storage, Event} = 64, + // pub type FellowshipTreasuryInstance = pallet_treasury::Instance1; + FellowshipTreasury: pallet_treasury::::{Pallet, Call, Storage, Event} = 65, // Ambassador Program. AmbassadorCollective: pallet_ranked_collective::::{Pallet, Call, Storage, Event} = 70, @@ -744,6 +765,8 @@ mod benches { [pallet_collective_content, AmbassadorContent] [pallet_core_fellowship, AmbassadorCore] [pallet_salary, AmbassadorSalary] + [pallet_treasury, FellowshipTreasury] + [pallet_asset_rate, AssetRate] ); } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs index d49a2905e7f7..77f76342a2ed 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs @@ -19,6 +19,7 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_alliance; +pub mod pallet_asset_rate; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_collective; @@ -38,6 +39,7 @@ pub mod pallet_salary_fellowship_salary; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs new file mode 100644 index 000000000000..51b0580f8575 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs @@ -0,0 +1,85 @@ +// 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 . + +//! Autogenerated weights for `pallet_asset_rate` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-28, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-westend-dev +// --steps=2 +// --repeat=2 +// --pallet=pallet-asset-rate +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/collectives/collectives-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_rate`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_rate::WeightInfo for WeightInfo { + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `4703` + // Minimum execution time: 102_000_000 picoseconds. + Weight::from_parts(112_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + fn update() -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `4703` + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(105_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + fn remove() -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `4703` + // Minimum execution time: 112_000_000 picoseconds. + Weight::from_parts(116_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs new file mode 100644 index 000000000000..58540e646d8c --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs @@ -0,0 +1,214 @@ +// 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 . + +//! Autogenerated weights for `pallet_treasury` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-28, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-westend-dev +// --steps=2 +// --repeat=2 +// --pallet=pallet-treasury +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/collectives/collectives-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_treasury`. +pub struct WeightInfo(PhantomData); +impl pallet_treasury::WeightInfo for WeightInfo { + /// Storage: `FellowshipTreasury::ProposalCount` (r:1 w:1) + /// Proof: `FellowshipTreasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Proposals` (r:0 w:1) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + fn spend_local() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1887` + // Minimum execution time: 117_000_000 picoseconds. + Weight::from_parts(126_000_000, 0) + .saturating_add(Weight::from_parts(0, 1887)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipTreasury::ProposalCount` (r:1 w:1) + /// Proof: `FellowshipTreasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Proposals` (r:0 w:1) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + fn propose_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `143` + // Estimated: `1489` + // Minimum execution time: 264_000_000 picoseconds. + Weight::from_parts(277_000_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipTreasury::Proposals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn reject_proposal() -> Weight { + // Proof Size summary in bytes: + // Measured: `301` + // Estimated: `3593` + // Minimum execution time: 289_000_000 picoseconds. + Weight::from_parts(312_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// The range of component `p` is `[0, 99]`. + fn approve_proposal(_p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + fn remove_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `1887` + // Minimum execution time: 62_000_000 picoseconds. + Weight::from_parts(65_000_000, 0) + .saturating_add(Weight::from_parts(0, 1887)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `System::Account` (r:199 w:199) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Deactivated` (r:1 w:1) + /// Proof: `FellowshipTreasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:1) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Proposals` (r:99 w:99) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 99]`. + fn on_initialize_proposals(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `145 + p * (250 ±0)` + // Estimated: `256707 + p * (5206 ±0)` + // Minimum execution time: 218_000_000 picoseconds. + Weight::from_parts(221_000_000, 0) + .saturating_add(Weight::from_parts(0, 256707)) + // Standard Error: 154_515 + .saturating_add(Weight::from_parts(399_232_323, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) + } + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::SpendCount` (r:1 w:1) + /// Proof: `FellowshipTreasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Spends` (r:0 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `4703` + // Minimum execution time: 163_000_000 picoseconds. + Weight::from_parts(171_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipTreasury::Spends` (r:1 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `629` + // Estimated: `5318` + // Minimum execution time: 472_000_000 picoseconds. + Weight::from_parts(492_000_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `FellowshipTreasury::Spends` (r:1 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5318` + // Minimum execution time: 211_000_000 picoseconds. + Weight::from_parts(215_000_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipTreasury::Spends` (r:1 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `179` + // Estimated: `5318` + // Minimum execution time: 124_000_000 picoseconds. + Weight::from_parts(126_000_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index 44d5d1daf326..9b5b709ab82e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -33,6 +33,7 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use westend_runtime_constants::xcm as xcm_constants; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -46,8 +47,6 @@ use xcm_builder::{ }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; -const FELLOWSHIP_ADMIN_INDEX: u32 = 1; - parameter_types! { pub const WndLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: Option = Some(NetworkId::Westend); @@ -57,7 +56,8 @@ parameter_types! { pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); - pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); + pub const FellowshipAdminBodyId: BodyId = BodyId::Index(xcm_constants::body::FELLOWSHIP_ADMIN_INDEX); + pub const TreasurerBodyId: BodyId = BodyId::Index(xcm_constants::body::TREASURER_INDEX); pub AssetHub: MultiLocation = (Parent, Parachain(1000)).into(); pub AssetHubUsdtId: AssetId = (PalletInstance(50), GeneralIndex(1984)).into(); pub UsdtAssetHub: LocatableAssetId = LocatableAssetId { diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 60e631a03ee2..d71c626cd98d 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -149,8 +149,11 @@ impl TryConvert<&VersionedMultiLocation, xcm::latest::MultiLocation> #[cfg(feature = "runtime-benchmarks")] pub mod benchmarks { use super::VersionedLocatableAsset; + use core::marker::PhantomData; + use frame_support::traits::Get; use pallet_asset_rate::AssetKindFactory; use pallet_treasury::ArgumentsFactory as TreasuryArgumentsFactory; + use sp_core::{ConstU32, ConstU8}; use xcm::prelude::*; /// Provides a factory method for the [`VersionedLocatableAsset`]. @@ -172,12 +175,22 @@ pub mod benchmarks { /// Provide factory methods for the [`VersionedLocatableAsset`] and the `Beneficiary` of the /// [`VersionedMultiLocation`]. The location of the asset is determined as a Parachain with an /// ID equal to the passed seed. - pub struct TreasuryArguments; - impl TreasuryArgumentsFactory - for TreasuryArguments + pub struct TreasuryArguments, ParaId = ConstU32<0>>( + PhantomData<(Parents, ParaId)>, + ); + impl, ParaId: Get> + TreasuryArgumentsFactory + for TreasuryArguments { fn create_asset_kind(seed: u32) -> VersionedLocatableAsset { - AssetRateArguments::create_asset_kind(seed) + VersionedLocatableAsset::V3 { + location: xcm::v3::MultiLocation::new(Parents::get(), X1(Parachain(ParaId::get()))), + asset_id: xcm::v3::MultiLocation::new( + 0, + X2(PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())), + ) + .into(), + } } fn create_beneficiary(seed: [u8; 32]) -> VersionedMultiLocation { VersionedMultiLocation::V3(xcm::v3::MultiLocation::new( diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index de3969afb711..c2bce3a1791b 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -124,6 +124,7 @@ pub mod xcm { const ROOT_INDEX: u32 = 0; // The bodies corresponding to the Polkadot OpenGov Origins. pub const FELLOWSHIP_ADMIN_INDEX: u32 = 1; + pub const TREASURER_INDEX: u32 = 2; } } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 9ab6470f6dae..d846b982e9af 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -21,7 +21,7 @@ use super::{ GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, TransactionByteFee, Treasury, WeightToFee, XcmPallet, }; - +use crate::governance::pallet_custom_origins::Treasurer; use frame_support::{ match_types, parameter_types, traits::{Everything, Nothing}, @@ -34,7 +34,9 @@ use runtime_common::{ }; use sp_core::ConstU32; use westend_runtime_constants::{ - currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, + currency::CENTS, + system_parachain::*, + xcm::body::{FELLOWSHIP_ADMIN_INDEX, TREASURER_INDEX}, }; use xcm::latest::prelude::*; use xcm_builder::{ @@ -198,6 +200,8 @@ parameter_types! { pub const StakingAdminBodyId: BodyId = BodyId::Defense; // FellowshipAdmin pluralistic body. pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); + // `Treasurer` pluralistic body. + pub const TreasurerBodyId: BodyId = BodyId::Index(TREASURER_INDEX); } /// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value. @@ -220,6 +224,9 @@ pub type StakingAdminToPlurality = pub type FellowshipAdminToPlurality = OriginToPluralityVoice; +/// Type to convert the `Treasurer` origin to a Plurality `MultiLocation` value. +pub type TreasurerToPlurality = OriginToPluralityVoice; + /// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an /// interior location of this chain for a destination chain. pub type LocalPalletOriginToLocation = ( @@ -229,6 +236,8 @@ pub type LocalPalletOriginToLocation = ( StakingAdminToPlurality, // FellowshipAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. FellowshipAdminToPlurality, + // `Treasurer` origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + TreasurerToPlurality, ); impl pallet_xcm::Config for Runtime { diff --git a/prdoc/pr_2532.prdoc b/prdoc/pr_2532.prdoc new file mode 100644 index 000000000000..d0df0ee4aca9 --- /dev/null +++ b/prdoc/pr_2532.prdoc @@ -0,0 +1,11 @@ +# 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: Westend Fellowship Treasury + +doc: + - audience: Runtime User + description: | + Treasury Pallet Instance for the Fellowship in Westend Collectives. + +crates: [ ] diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index 61fe29dafcae..0b9999e37fbe 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -78,8 +78,7 @@ fn create_approved_proposals, I: 'static>(n: u32) -> Result<(), &'s #[allow(deprecated)] Treasury::::propose_spend(RawOrigin::Signed(caller).into(), value, lookup)?; let proposal_id = >::get() - 1; - #[allow(deprecated)] - Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; + Approvals::::try_append(proposal_id).unwrap(); } ensure!(>::get().len() == n as usize, "Not all approved"); Ok(()) @@ -163,6 +162,8 @@ mod benchmarks { fn approve_proposal( p: Linear<0, { T::MaxApprovals::get() - 1 }>, ) -> Result<(), BenchmarkError> { + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; create_approved_proposals::(p)?; let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] @@ -172,8 +173,6 @@ mod benchmarks { beneficiary_lookup, )?; let proposal_id = Treasury::::proposal_count() - 1; - let approve_origin = - T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; #[extrinsic_call] _(approve_origin as T::RuntimeOrigin, proposal_id); @@ -191,8 +190,7 @@ mod benchmarks { beneficiary_lookup, )?; let proposal_id = Treasury::::proposal_count() - 1; - #[allow(deprecated)] - Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; + Approvals::::try_append(proposal_id).unwrap(); let reject_origin = T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;