mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Treasury spends various asset kinds (#1333)
### Summary This PR introduces new dispatchables to the treasury pallet, allowing spends of various asset types. The enhanced features of the treasury pallet, in conjunction with the asset-rate pallet, are set up and enabled for Westend and Rococo. ### Westend and Rococo runtimes. Polkadot/Kusams/Rococo Treasury can accept proposals for `spends` of various asset kinds by specifying the asset's location and ID. #### Treasury Instance New Dispatchables: - `spend(AssetKind, AssetBalance, Beneficiary, Option<ValidFrom>)` - propose and approve a spend; - `payout(SpendIndex)` - payout an approved spend or retry a failed payout - `check_payment(SpendIndex)` - check the status of a payout; - `void_spend(SpendIndex)` - void previously approved spend; > existing spend dispatchable renamed to spend_local in this context, the `AssetKind` parameter contains the asset's location and it's corresponding `asset_id`, for example: `USDT` on `AssetHub`, ``` rust location = MultiLocation(0, X1(Parachain(1000))) asset_id = MultiLocation(0, X2(PalletInstance(50), GeneralIndex(1984))) ``` the `Beneficiary` parameter is a `MultiLocation` in the context of the asset's location, for example ``` rust // the Fellowship salary pallet's location / account FellowshipSalaryPallet = MultiLocation(1, X2(Parachain(1001), PalletInstance(64))) // or custom `AccountId` Alice = MultiLocation(0, AccountId32(network: None, id: [1,...])) ``` the `AssetBalance` represents the amount of the `AssetKind` to be transferred to the `Beneficiary`. For permission checks, the asset amount is converted to the native amount and compared against the maximum spendable amount determined by the commanding spend origin. the `spend` dispatchable allows for batching spends with different `ValidFrom` arguments, enabling milestone-based spending. If the expectations tied to an approved spend are not met, it is possible to void the spend later using the `void_spend` dispatchable. Asset Rate Pallet provides the conversion rate from the `AssetKind` to the native balance. #### Asset Rate Instance Dispatchables: - `create(AssetKind, Rate)` - initialize a conversion rate to the native balance for the given asset - `update(AssetKind, Rate)` - update the conversion rate to the native balance for the given asset - `remove(AssetKind)` - remove an existing conversion rate to the native balance for the given asset the pallet's dispatchables can be executed by the Root or Treasurer origins. ### Treasury Pallet Treasury Pallet can accept proposals for `spends` of various asset kinds and pay them out through the implementation of the `Pay` trait. New Dispatchables: - `spend(Config::AssetKind, AssetBalance, Config::Beneficiary, Option<ValidFrom>)` - propose and approve a spend; - `payout(SpendIndex)` - payout an approved spend or retry a failed payout; - `check_payment(SpendIndex)` - check the status of a payout; - `void_spend(SpendIndex)` - void previously approved spend; > existing spend dispatchable renamed to spend_local The parameters' types of the `spend` dispatchable exposed via the pallet's `Config` and allows to propose and accept a spend of a certain amount. An approved spend can be claimed via the `payout` within the `Config::SpendPeriod`. Clients provide an implementation of the `Pay` trait which can pay an asset of the `AssetKind` to the `Beneficiary` in `AssetBalance` units. The implementation of the Pay trait might not have an immediate final payment status, for example if implemented over `XCM` and the actual transfer happens on a remote chain. The `check_status` dispatchable can be executed to update the spend's payment state and retry the `payout` if the payment has failed. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: command-bot <>
This commit is contained in:
Generated
+12
@@ -840,20 +840,27 @@ version = "1.0.0"
|
||||
dependencies = [
|
||||
"assert_matches",
|
||||
"asset-hub-westend-runtime",
|
||||
"cumulus-pallet-dmp-queue",
|
||||
"cumulus-pallet-parachain-system",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"integration-tests-common",
|
||||
"pallet-asset-conversion",
|
||||
"pallet-asset-rate",
|
||||
"pallet-assets",
|
||||
"pallet-balances",
|
||||
"pallet-treasury",
|
||||
"pallet-xcm",
|
||||
"parachains-common",
|
||||
"parity-scale-codec",
|
||||
"polkadot-core-primitives",
|
||||
"polkadot-parachain-primitives",
|
||||
"polkadot-runtime-common",
|
||||
"polkadot-runtime-parachains",
|
||||
"sp-runtime",
|
||||
"staging-xcm",
|
||||
"staging-xcm-builder",
|
||||
"staging-xcm-executor",
|
||||
"xcm-emulator",
|
||||
]
|
||||
|
||||
@@ -10567,6 +10574,7 @@ dependencies = [
|
||||
name = "pallet-treasury"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"docify",
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
@@ -12485,6 +12493,7 @@ dependencies = [
|
||||
"impl-trait-for-tuples",
|
||||
"libsecp256k1",
|
||||
"log",
|
||||
"pallet-asset-rate",
|
||||
"pallet-authorship",
|
||||
"pallet-babe",
|
||||
"pallet-balances",
|
||||
@@ -12519,6 +12528,7 @@ dependencies = [
|
||||
"sp-staking",
|
||||
"sp-std",
|
||||
"staging-xcm",
|
||||
"staging-xcm-builder",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
@@ -13900,6 +13910,7 @@ dependencies = [
|
||||
"frame-try-runtime",
|
||||
"hex-literal",
|
||||
"log",
|
||||
"pallet-asset-rate",
|
||||
"pallet-authority-discovery",
|
||||
"pallet-authorship",
|
||||
"pallet-babe",
|
||||
@@ -19941,6 +19952,7 @@ dependencies = [
|
||||
"frame-try-runtime",
|
||||
"hex-literal",
|
||||
"log",
|
||||
"pallet-asset-rate",
|
||||
"pallet-authority-discovery",
|
||||
"pallet-authorship",
|
||||
"pallet-babe",
|
||||
|
||||
@@ -18,17 +18,24 @@ frame-system = { path = "../../../../../../substrate/frame/system", default-feat
|
||||
pallet-balances = { path = "../../../../../../substrate/frame/balances", default-features = false}
|
||||
pallet-assets = { path = "../../../../../../substrate/frame/assets", default-features = false}
|
||||
pallet-asset-conversion = { path = "../../../../../../substrate/frame/asset-conversion", default-features = false}
|
||||
pallet-treasury = { path = "../../../../../../substrate/frame/treasury", default-features = false}
|
||||
pallet-asset-rate = { path = "../../../../../../substrate/frame/asset-rate", default-features = false}
|
||||
|
||||
# Polkadot
|
||||
polkadot-core-primitives = { path = "../../../../../../polkadot/core-primitives", default-features = false}
|
||||
polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain", default-features = false}
|
||||
polkadot-runtime-common = { path = "../../../../../../polkadot/runtime/common" }
|
||||
polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" }
|
||||
xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false}
|
||||
xcm-builder = { package = "staging-xcm-builder", path = "../../../../../../polkadot/xcm/xcm-builder", 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}
|
||||
|
||||
# Cumulus
|
||||
parachains-common = { path = "../../../../common" }
|
||||
asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" }
|
||||
cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../pallets/dmp-queue" }
|
||||
cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../pallets/parachain-system" }
|
||||
|
||||
# Local
|
||||
xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false}
|
||||
@@ -37,15 +44,21 @@ integration-tests-common = { path = "../../common", default-features = false}
|
||||
[features]
|
||||
runtime-benchmarks = [
|
||||
"asset-hub-westend-runtime/runtime-benchmarks",
|
||||
"cumulus-pallet-parachain-system/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
"integration-tests-common/runtime-benchmarks",
|
||||
"pallet-asset-conversion/runtime-benchmarks",
|
||||
"pallet-asset-rate/runtime-benchmarks",
|
||||
"pallet-assets/runtime-benchmarks",
|
||||
"pallet-balances/runtime-benchmarks",
|
||||
"pallet-treasury/runtime-benchmarks",
|
||||
"pallet-xcm/runtime-benchmarks",
|
||||
"parachains-common/runtime-benchmarks",
|
||||
"polkadot-parachain-primitives/runtime-benchmarks",
|
||||
"polkadot-runtime-common/runtime-benchmarks",
|
||||
"polkadot-runtime-parachains/runtime-benchmarks",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
"xcm-executor/runtime-benchmarks",
|
||||
]
|
||||
|
||||
+1
@@ -18,3 +18,4 @@ mod send;
|
||||
mod set_xcm_versions;
|
||||
mod swap;
|
||||
mod teleport;
|
||||
mod treasury;
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
// 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 frame_support::traits::fungibles::{Create, Inspect, Mutate};
|
||||
use integration_tests_common::constants::accounts::{ALICE, BOB};
|
||||
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, PalletInstance(37));
|
||||
// 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(0, Parachain(AssetHubWestend::para_id().into()));
|
||||
let root = <Westend as Chain>::RuntimeOrigin::root();
|
||||
// asset kind to be spend 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 = Westend::account_id_of(BOB);
|
||||
let bob_signed = <Westend as Chain>::RuntimeOrigin::signed(bob.clone());
|
||||
|
||||
AssetHubWestend::execute_with(|| {
|
||||
type Assets = <AssetHubWestend as AssetHubWestendPallet>::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 Inspect<_>>::balance(ASSET_ID, &alice,), 0u128,);
|
||||
});
|
||||
|
||||
Westend::execute_with(|| {
|
||||
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
|
||||
type Treasury = <Westend as WestendPallet>::Treasury;
|
||||
type AssetRate = <Westend as WestendPallet>::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(MultiLocation::new(0, Into::<[u8; 32]>::into(alice.clone())).into()),
|
||||
None,
|
||||
));
|
||||
// claim the spend.
|
||||
assert_ok!(Treasury::payout(bob_signed.clone(), 0));
|
||||
|
||||
assert_expected_events!(
|
||||
Westend,
|
||||
vec![
|
||||
RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
AssetHubWestend::execute_with(|| {
|
||||
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
|
||||
type Assets = <AssetHubWestend as AssetHubWestendPallet>::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!(
|
||||
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::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {},
|
||||
RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { outcome: Outcome::Complete(..) ,.. }) => {},
|
||||
]
|
||||
);
|
||||
// beneficiary received the assets from the treasury.
|
||||
assert_eq!(<Assets as Inspect<_>>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,);
|
||||
});
|
||||
|
||||
Westend::execute_with(|| {
|
||||
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
|
||||
type Treasury = <Westend as WestendPallet>::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!(
|
||||
Westend,
|
||||
vec![
|
||||
RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {},
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -46,6 +46,8 @@ decl_test_relay_chains! {
|
||||
XcmPallet: westend_runtime::XcmPallet,
|
||||
Sudo: westend_runtime::Sudo,
|
||||
Balances: westend_runtime::Balances,
|
||||
Treasury: westend_runtime::Treasury,
|
||||
AssetRate: westend_runtime::AssetRate,
|
||||
}
|
||||
},
|
||||
#[api_version(7)]
|
||||
|
||||
@@ -38,11 +38,12 @@ use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter,
|
||||
DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FungiblesAdapter, IsConcrete,
|
||||
LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
|
||||
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
|
||||
SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId,
|
||||
UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||
DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal,
|
||||
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NativeAsset,
|
||||
NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||
};
|
||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||
|
||||
@@ -75,6 +76,9 @@ pub type LocationToAccountId = (
|
||||
SiblingParachainConvertsVia<Sibling, AccountId>,
|
||||
// Straight up local `AccountId32` origins just alias directly to `AccountId`.
|
||||
AccountId32Aliases<RelayNetwork, AccountId>,
|
||||
// Foreign chain account alias into local accounts according to a hash of their standard
|
||||
// description.
|
||||
HashedDescription<AccountId, DescribeFamily<DescribePalletTerminal>>,
|
||||
);
|
||||
|
||||
/// Means for transacting the native currency on this chain.
|
||||
@@ -222,6 +226,9 @@ match_types! {
|
||||
MultiLocation { parents: 1, interior: Here } |
|
||||
MultiLocation { parents: 1, interior: X1(Plurality { .. }) }
|
||||
};
|
||||
pub type TreasuryPallet: impl Contains<MultiLocation> = {
|
||||
MultiLocation { parents: 1, interior: X1(PalletInstance(37)) }
|
||||
};
|
||||
}
|
||||
|
||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly
|
||||
@@ -449,8 +456,9 @@ pub type Barrier = TrailingSetTopicAsId<
|
||||
// If the message is one that immediately attemps to pay for execution, then
|
||||
// allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Parent and its pluralities (i.e. governance bodies) get free execution.
|
||||
AllowExplicitUnpaidExecutionFrom<ParentOrParentsPlurality>,
|
||||
// Parent, its pluralities (i.e. governance bodies) and treasury pallet get
|
||||
// free execution.
|
||||
AllowExplicitUnpaidExecutionFrom<(ParentOrParentsPlurality, TreasuryPallet)>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<Everything>,
|
||||
),
|
||||
|
||||
@@ -38,6 +38,7 @@ pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-featur
|
||||
pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = false }
|
||||
pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false }
|
||||
pallet-treasury = { path = "../../../substrate/frame/treasury", default-features = false }
|
||||
pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false }
|
||||
pallet-election-provider-multi-phase = { path = "../../../substrate/frame/election-provider-multi-phase", default-features = false }
|
||||
frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false }
|
||||
|
||||
@@ -50,6 +51,7 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac
|
||||
|
||||
slot-range-helper = { path = "slot_range_helper", default-features = false }
|
||||
xcm = { package = "staging-xcm", path = "../../xcm", default-features = false }
|
||||
xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.4.1"
|
||||
@@ -74,6 +76,7 @@ std = [
|
||||
"inherents/std",
|
||||
"libsecp256k1/std",
|
||||
"log/std",
|
||||
"pallet-asset-rate/std",
|
||||
"pallet-authorship/std",
|
||||
"pallet-balances/std",
|
||||
"pallet-election-provider-multi-phase/std",
|
||||
@@ -100,6 +103,7 @@ std = [
|
||||
"sp-session/std",
|
||||
"sp-staking/std",
|
||||
"sp-std/std",
|
||||
"xcm-builder/std",
|
||||
"xcm/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
@@ -109,6 +113,7 @@ runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks",
|
||||
"libsecp256k1/hmac",
|
||||
"libsecp256k1/static-context",
|
||||
"pallet-asset-rate/runtime-benchmarks",
|
||||
"pallet-babe/runtime-benchmarks",
|
||||
"pallet-balances/runtime-benchmarks",
|
||||
"pallet-election-provider-multi-phase/runtime-benchmarks",
|
||||
@@ -121,12 +126,14 @@ runtime-benchmarks = [
|
||||
"runtime-parachains/runtime-benchmarks",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
"sp-staking/runtime-benchmarks",
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-election-provider-support/try-runtime",
|
||||
"frame-support-test/try-runtime",
|
||||
"frame-support/try-runtime",
|
||||
"frame-system/try-runtime",
|
||||
"pallet-asset-rate/try-runtime",
|
||||
"pallet-authorship/try-runtime",
|
||||
"pallet-babe?/try-runtime",
|
||||
"pallet-balances/try-runtime",
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
|
||||
use crate::NegativeImbalance;
|
||||
use frame_support::traits::{Currency, Imbalance, OnUnbalanced};
|
||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||
use primitives::Balance;
|
||||
use sp_runtime::Perquintill;
|
||||
use sp_runtime::{traits::TryConvert, Perquintill, RuntimeDebug};
|
||||
use xcm::VersionedMultiLocation;
|
||||
|
||||
/// Logic for the author to get a portion of fees.
|
||||
pub struct ToAuthor<R>(sp_std::marker::PhantomData<R>);
|
||||
@@ -98,13 +100,104 @@ pub fn era_payout(
|
||||
(staking_payout, rest)
|
||||
}
|
||||
|
||||
/// Versioned locatable asset type which contains both an XCM `location` and `asset_id` to identify
|
||||
/// an asset which exists on some chain.
|
||||
#[derive(
|
||||
Encode, Decode, Eq, PartialEq, Clone, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
pub enum VersionedLocatableAsset {
|
||||
#[codec(index = 3)]
|
||||
V3 {
|
||||
/// The (relative) location in which the asset ID is meaningful.
|
||||
location: xcm::v3::MultiLocation,
|
||||
/// The asset's ID.
|
||||
asset_id: xcm::v3::AssetId,
|
||||
},
|
||||
}
|
||||
|
||||
/// Converts the [`VersionedLocatableAsset`] to the [`xcm_builder::LocatableAssetId`].
|
||||
pub struct LocatableAssetConverter;
|
||||
impl TryConvert<VersionedLocatableAsset, xcm_builder::LocatableAssetId>
|
||||
for LocatableAssetConverter
|
||||
{
|
||||
fn try_convert(
|
||||
asset: VersionedLocatableAsset,
|
||||
) -> Result<xcm_builder::LocatableAssetId, VersionedLocatableAsset> {
|
||||
match asset {
|
||||
VersionedLocatableAsset::V3 { location, asset_id } =>
|
||||
Ok(xcm_builder::LocatableAssetId { asset_id, location }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the [`VersionedMultiLocation`] to the [`xcm::latest::MultiLocation`].
|
||||
pub struct VersionedMultiLocationConverter;
|
||||
impl TryConvert<&VersionedMultiLocation, xcm::latest::MultiLocation>
|
||||
for VersionedMultiLocationConverter
|
||||
{
|
||||
fn try_convert(
|
||||
location: &VersionedMultiLocation,
|
||||
) -> Result<xcm::latest::MultiLocation, &VersionedMultiLocation> {
|
||||
let latest = match location.clone() {
|
||||
VersionedMultiLocation::V2(l) => l.try_into().map_err(|_| location)?,
|
||||
VersionedMultiLocation::V3(l) => l,
|
||||
};
|
||||
Ok(latest)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub mod benchmarks {
|
||||
use super::VersionedLocatableAsset;
|
||||
use pallet_asset_rate::AssetKindFactory;
|
||||
use pallet_treasury::ArgumentsFactory as TreasuryArgumentsFactory;
|
||||
use xcm::prelude::*;
|
||||
|
||||
/// Provides a factory method for the [`VersionedLocatableAsset`].
|
||||
/// The location of the asset is determined as a Parachain with an ID equal to the passed seed.
|
||||
pub struct AssetRateArguments;
|
||||
impl AssetKindFactory<VersionedLocatableAsset> for AssetRateArguments {
|
||||
fn create_asset_kind(seed: u32) -> VersionedLocatableAsset {
|
||||
VersionedLocatableAsset::V3 {
|
||||
location: xcm::v3::MultiLocation::new(0, X1(Parachain(seed))),
|
||||
asset_id: xcm::v3::MultiLocation::new(
|
||||
0,
|
||||
X2(PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())),
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<VersionedLocatableAsset, VersionedMultiLocation>
|
||||
for TreasuryArguments
|
||||
{
|
||||
fn create_asset_kind(seed: u32) -> VersionedLocatableAsset {
|
||||
AssetRateArguments::create_asset_kind(seed)
|
||||
}
|
||||
fn create_beneficiary(seed: [u8; 32]) -> VersionedMultiLocation {
|
||||
VersionedMultiLocation::V3(xcm::v3::MultiLocation::new(
|
||||
0,
|
||||
X1(AccountId32 { network: None, id: seed }),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use frame_support::{
|
||||
dispatch::DispatchClass,
|
||||
parameter_types,
|
||||
traits::{ConstU32, FindAuthor},
|
||||
traits::{
|
||||
tokens::{PayFromAccount, UnityAssetBalanceConversion},
|
||||
ConstU32, FindAuthor,
|
||||
},
|
||||
weights::Weight,
|
||||
PalletId,
|
||||
};
|
||||
@@ -189,6 +282,7 @@ mod tests {
|
||||
parameter_types! {
|
||||
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
|
||||
pub const MaxApprovals: u32 = 100;
|
||||
pub TreasuryAccount: AccountId = Treasury::account_id();
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config for Test {
|
||||
@@ -208,6 +302,14 @@ mod tests {
|
||||
type MaxApprovals = MaxApprovals;
|
||||
type WeightInfo = ();
|
||||
type SpendOrigin = frame_support::traits::NeverEnsureOrigin<u64>;
|
||||
type AssetKind = ();
|
||||
type Beneficiary = Self::AccountId;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::AccountId>;
|
||||
type Paymaster = PayFromAccount<Balances, TreasuryAccount>;
|
||||
type BalanceConverter = UnityAssetBalanceConversion;
|
||||
type PayoutPeriod = ConstU64<0>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
pub struct OneAuthor;
|
||||
|
||||
@@ -52,6 +52,7 @@ pallet-collective = { path = "../../../substrate/frame/collective", default-feat
|
||||
pallet-conviction-voting = { path = "../../../substrate/frame/conviction-voting", default-features = false }
|
||||
pallet-democracy = { path = "../../../substrate/frame/democracy", default-features = false }
|
||||
pallet-elections-phragmen = { path = "../../../substrate/frame/elections-phragmen", default-features = false }
|
||||
pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false }
|
||||
frame-executive = { path = "../../../substrate/frame/executive", default-features = false }
|
||||
pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false }
|
||||
pallet-identity = { path = "../../../substrate/frame/identity", default-features = false }
|
||||
@@ -72,7 +73,7 @@ pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-featur
|
||||
pallet-session = { path = "../../../substrate/frame/session", default-features = false }
|
||||
pallet-society = { path = "../../../substrate/frame/society", default-features = false }
|
||||
pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false }
|
||||
frame-support = { path = "../../../substrate/frame/support", default-features = false }
|
||||
frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["tuples-96"] }
|
||||
pallet-staking = { path = "../../../substrate/frame/staking", default-features = false }
|
||||
frame-system = { path = "../../../substrate/frame/system", default-features = false }
|
||||
frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false }
|
||||
@@ -131,6 +132,7 @@ std = [
|
||||
"inherents/std",
|
||||
"log/std",
|
||||
"offchain-primitives/std",
|
||||
"pallet-asset-rate/std",
|
||||
"pallet-authority-discovery/std",
|
||||
"pallet-authorship/std",
|
||||
"pallet-babe/std",
|
||||
@@ -207,6 +209,7 @@ runtime-benchmarks = [
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system-benchmarking/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
"pallet-asset-rate/runtime-benchmarks",
|
||||
"pallet-babe/runtime-benchmarks",
|
||||
"pallet-balances/runtime-benchmarks",
|
||||
"pallet-bounties/runtime-benchmarks",
|
||||
@@ -258,6 +261,7 @@ try-runtime = [
|
||||
"frame-system/try-runtime",
|
||||
"frame-try-runtime",
|
||||
"frame-try-runtime/try-runtime",
|
||||
"pallet-asset-rate/try-runtime",
|
||||
"pallet-authority-discovery/try-runtime",
|
||||
"pallet-authorship/try-runtime",
|
||||
"pallet-babe/try-runtime",
|
||||
|
||||
@@ -30,7 +30,10 @@ use primitives::{
|
||||
ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID,
|
||||
};
|
||||
use runtime_common::{
|
||||
assigned_slots, auctions, claims, crowdloan, impl_runtime_weights, impls::ToAuthor,
|
||||
assigned_slots, auctions, claims, crowdloan, impl_runtime_weights,
|
||||
impls::{
|
||||
LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedMultiLocationConverter,
|
||||
},
|
||||
paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BlockHashCount, BlockLength,
|
||||
SlowAdjustingFeeUpdate,
|
||||
};
|
||||
@@ -79,7 +82,8 @@ use sp_runtime::{
|
||||
create_runtime_str, generic, impl_opaque_keys,
|
||||
traits::{
|
||||
AccountIdLookup, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto,
|
||||
Extrinsic as ExtrinsicT, Keccak256, OpaqueKeys, SaturatedConversion, Verify,
|
||||
Extrinsic as ExtrinsicT, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion,
|
||||
Verify,
|
||||
},
|
||||
transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug,
|
||||
@@ -88,7 +92,11 @@ use sp_staking::SessionIndex;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
use sp_version::NativeVersion;
|
||||
use sp_version::RuntimeVersion;
|
||||
use xcm::latest::Junction;
|
||||
use xcm::{
|
||||
latest::{InteriorMultiLocation, Junction, Junction::PalletInstance},
|
||||
VersionedMultiLocation,
|
||||
};
|
||||
use xcm_builder::PayOverXcm;
|
||||
|
||||
pub use frame_system::Call as SystemCall;
|
||||
pub use pallet_balances::Call as BalancesCall;
|
||||
@@ -385,6 +393,10 @@ parameter_types! {
|
||||
pub const SpendPeriod: BlockNumber = 6 * DAYS;
|
||||
pub const Burn: Permill = Permill::from_perthousand(2);
|
||||
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
|
||||
pub const PayoutSpendPeriod: BlockNumber = 30 * DAYS;
|
||||
// The asset's interior location for the paying account. This is the Treasury
|
||||
// pallet instance (which sits at index 18).
|
||||
pub TreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(18).into();
|
||||
|
||||
pub const TipCountdown: BlockNumber = 1 * DAYS;
|
||||
pub const TipFindersFee: Percent = Percent::from_percent(20);
|
||||
@@ -394,6 +406,7 @@ parameter_types! {
|
||||
pub const MaxAuthorities: u32 = 100_000;
|
||||
pub const MaxKeys: u32 = 10_000;
|
||||
pub const MaxPeerInHeartbeats: u32 = 10_000;
|
||||
pub const MaxBalance: Balance = Balance::max_value();
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config for Runtime {
|
||||
@@ -413,6 +426,23 @@ impl pallet_treasury::Config for Runtime {
|
||||
type WeightInfo = weights::pallet_treasury::WeightInfo<Runtime>;
|
||||
type SpendFunds = Bounties;
|
||||
type SpendOrigin = TreasurySpender;
|
||||
type AssetKind = VersionedLocatableAsset;
|
||||
type Beneficiary = VersionedMultiLocation;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = PayOverXcm<
|
||||
TreasuryInteriorLocation,
|
||||
crate::xcm_config::XcmRouter,
|
||||
crate::XcmPallet,
|
||||
ConstU32<{ 6 * HOURS }>,
|
||||
Self::Beneficiary,
|
||||
Self::AssetKind,
|
||||
LocatableAssetConverter,
|
||||
VersionedMultiLocationConverter,
|
||||
>;
|
||||
type BalanceConverter = AssetRate;
|
||||
type PayoutPeriod = PayoutSpendPeriod;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -1202,6 +1232,18 @@ impl pallet_sudo::Config for Runtime {
|
||||
type WeightInfo = weights::pallet_sudo::WeightInfo<Runtime>;
|
||||
}
|
||||
|
||||
impl pallet_asset_rate::Config for Runtime {
|
||||
type WeightInfo = weights::pallet_asset_rate::WeightInfo<Runtime>;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type CreateOrigin = EnsureRoot<AccountId>;
|
||||
type RemoveOrigin = EnsureRoot<AccountId>;
|
||||
type UpdateOrigin = EnsureRoot<AccountId>;
|
||||
type Currency = Balances;
|
||||
type AssetKind = <Runtime as pallet_treasury::Config>::AssetKind;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments;
|
||||
}
|
||||
|
||||
construct_runtime! {
|
||||
pub enum Runtime
|
||||
{
|
||||
@@ -1279,6 +1321,9 @@ construct_runtime! {
|
||||
// Preimage registrar.
|
||||
Preimage: pallet_preimage::{Pallet, Call, Storage, Event<T>, HoldReason} = 32,
|
||||
|
||||
// Asset rate.
|
||||
AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event<T>} = 39,
|
||||
|
||||
// Bounties modules.
|
||||
Bounties: pallet_bounties::{Pallet, Call, Storage, Event<T>} = 35,
|
||||
ChildBounties: pallet_child_bounties = 40,
|
||||
@@ -1465,6 +1510,7 @@ mod benches {
|
||||
[pallet_treasury, Treasury]
|
||||
[pallet_utility, Utility]
|
||||
[pallet_vesting, Vesting]
|
||||
[pallet_asset_rate, AssetRate]
|
||||
[pallet_whitelist, Whitelist]
|
||||
// XCM
|
||||
[pallet_xcm, XcmPallet]
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
//! A list of the different weight modules for our runtime.
|
||||
|
||||
pub mod frame_system;
|
||||
pub mod pallet_asset_rate;
|
||||
pub mod pallet_balances;
|
||||
pub mod pallet_balances_nis_counterpart_balances;
|
||||
pub mod pallet_bounties;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot 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.
|
||||
|
||||
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Autogenerated weights for `pallet_asset_rate`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-07-03, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `cob`, CPU: `<UNKNOWN>`
|
||||
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/debug/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=rococo-dev
|
||||
// --steps=50
|
||||
// --repeat=2
|
||||
// --pallet=pallet_asset_rate
|
||||
// --extrinsic=*
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./runtime/rococo/src/weights/
|
||||
// --header=./file_header.txt
|
||||
|
||||
#![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<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_asset_rate::WeightInfo for WeightInfo<T> {
|
||||
/// Storage: AssetRate ConversionRateToNative (r:1 w:1)
|
||||
/// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen)
|
||||
fn create() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 143_000_000 picoseconds.
|
||||
Weight::from_parts(155_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.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(1237), added: 3712, mode: MaxEncodedLen)
|
||||
fn update() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `110`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 156_000_000 picoseconds.
|
||||
Weight::from_parts(172_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.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(1237), added: 3712, mode: MaxEncodedLen)
|
||||
fn remove() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `110`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 150_000_000 picoseconds.
|
||||
Weight::from_parts(160_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.saturating_add(T::DbWeight::get().reads(1))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
}
|
||||
@@ -17,24 +17,24 @@
|
||||
//! Autogenerated weights for `pallet_treasury`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2023-07-07, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
|
||||
//! HOSTNAME: `cob`, CPU: `<UNKNOWN>`
|
||||
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/polkadot
|
||||
// ./target/debug/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=rococo-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --repeat=2
|
||||
// --pallet=pallet_treasury
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --header=./file_header.txt
|
||||
// --heap-pages=4096
|
||||
// --output=./runtime/rococo/src/weights/
|
||||
// --header=./file_header.txt
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -47,13 +47,21 @@ use core::marker::PhantomData;
|
||||
/// Weight functions for `pallet_treasury`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_treasury::WeightInfo for WeightInfo<T> {
|
||||
fn spend() -> Weight {
|
||||
/// Storage: Treasury ProposalCount (r:1 w:1)
|
||||
/// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:0 w:1)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
fn spend_local() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 204_000 picoseconds.
|
||||
Weight::from_parts(233_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 0))
|
||||
// Measured: `42`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 177_000_000 picoseconds.
|
||||
Weight::from_parts(191_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: Treasury ProposalCount (r:1 w:1)
|
||||
/// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
@@ -61,10 +69,10 @@ impl<T: frame_system::Config> pallet_treasury::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
fn propose_spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `107`
|
||||
// Measured: `143`
|
||||
// Estimated: `1489`
|
||||
// Minimum execution time: 27_592_000 picoseconds.
|
||||
Weight::from_parts(27_960_000, 0)
|
||||
// Minimum execution time: 354_000_000 picoseconds.
|
||||
Weight::from_parts(376_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1489))
|
||||
.saturating_add(T::DbWeight::get().reads(1))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
@@ -75,10 +83,10 @@ impl<T: frame_system::Config> pallet_treasury::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
|
||||
fn reject_proposal() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `265`
|
||||
// Measured: `301`
|
||||
// Estimated: `3593`
|
||||
// Minimum execution time: 40_336_000 picoseconds.
|
||||
Weight::from_parts(41_085_000, 0)
|
||||
// Minimum execution time: 547_000_000 picoseconds.
|
||||
Weight::from_parts(550_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3593))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
@@ -90,13 +98,13 @@ impl<T: frame_system::Config> pallet_treasury::WeightInfo for WeightInfo<T> {
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn approve_proposal(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `433 + p * (8 ±0)`
|
||||
// Measured: `470 + p * (8 ±0)`
|
||||
// Estimated: `3573`
|
||||
// Minimum execution time: 9_938_000 picoseconds.
|
||||
Weight::from_parts(12_061_206, 0)
|
||||
// Minimum execution time: 104_000_000 picoseconds.
|
||||
Weight::from_parts(121_184_402, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3573))
|
||||
// Standard Error: 801
|
||||
.saturating_add(Weight::from_parts(26_602, 0).saturating_mul(p.into()))
|
||||
// Standard Error: 42_854
|
||||
.saturating_add(Weight::from_parts(153_112, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
@@ -104,10 +112,10 @@ impl<T: frame_system::Config> pallet_treasury::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
fn remove_approval() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `90`
|
||||
// Measured: `127`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 7_421_000 picoseconds.
|
||||
Weight::from_parts(7_620_000, 0)
|
||||
// Minimum execution time: 80_000_000 picoseconds.
|
||||
Weight::from_parts(82_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1887))
|
||||
.saturating_add(T::DbWeight::get().reads(1))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
@@ -118,26 +126,98 @@ impl<T: frame_system::Config> pallet_treasury::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:100 w:100)
|
||||
/// Storage: Treasury Proposals (r:99 w:99)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
/// Storage: System Account (r:201 w:201)
|
||||
/// Storage: System Account (r:199 w:199)
|
||||
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
|
||||
/// Storage: Bounties BountyApprovals (r:1 w:1)
|
||||
/// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// The range of component `p` is `[0, 100]`.
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn on_initialize_proposals(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `296 + p * (251 ±0)`
|
||||
// Measured: `331 + p * (251 ±0)`
|
||||
// Estimated: `3593 + p * (5206 ±0)`
|
||||
// Minimum execution time: 62_706_000 picoseconds.
|
||||
Weight::from_parts(61_351_470, 0)
|
||||
// Minimum execution time: 887_000_000 picoseconds.
|
||||
Weight::from_parts(828_616_021, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3593))
|
||||
// Standard Error: 32_787
|
||||
.saturating_add(Weight::from_parts(37_873_920, 0).saturating_mul(p.into()))
|
||||
// Standard Error: 695_351
|
||||
.saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into())))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
.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(1237), added: 3712, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury SpendCount (r:1 w:1)
|
||||
/// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Spends (r:0 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
fn spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `114`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 208_000_000 picoseconds.
|
||||
Weight::from_parts(222_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
/// Storage: XcmPallet QueryCounter (r:1 w:1)
|
||||
/// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
|
||||
/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet Queries (r:0 w:1)
|
||||
/// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured)
|
||||
fn payout() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `737`
|
||||
// Estimated: `5313`
|
||||
// Minimum execution time: 551_000_000 picoseconds.
|
||||
Weight::from_parts(569_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 5313))
|
||||
.saturating_add(T::DbWeight::get().reads(9))
|
||||
.saturating_add(T::DbWeight::get().writes(6))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
/// Storage: XcmPallet Queries (r:1 w:1)
|
||||
/// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured)
|
||||
fn check_status() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `442`
|
||||
// Estimated: `5313`
|
||||
// Minimum execution time: 245_000_000 picoseconds.
|
||||
Weight::from_parts(281_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 5313))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
fn void_spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `172`
|
||||
// Estimated: `5313`
|
||||
// Minimum execution time: 147_000_000 picoseconds.
|
||||
Weight::from_parts(160_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 5313))
|
||||
.saturating_add(T::DbWeight::get().reads(1))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,11 @@ sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", def
|
||||
|
||||
frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false }
|
||||
frame-executive = { path = "../../../substrate/frame/executive", default-features = false }
|
||||
frame-support = { path = "../../../substrate/frame/support", default-features = false }
|
||||
frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["tuples-96"] }
|
||||
frame-system = { path = "../../../substrate/frame/system", default-features = false }
|
||||
frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false }
|
||||
westend-runtime-constants = { package = "westend-runtime-constants", path = "constants", default-features = false }
|
||||
pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-features = false }
|
||||
pallet-authority-discovery = { path = "../../../substrate/frame/authority-discovery", default-features = false }
|
||||
pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false }
|
||||
pallet-babe = { path = "../../../substrate/frame/babe", default-features = false }
|
||||
@@ -143,6 +144,7 @@ std = [
|
||||
"inherents/std",
|
||||
"log/std",
|
||||
"offchain-primitives/std",
|
||||
"pallet-asset-rate/std",
|
||||
"pallet-authority-discovery/std",
|
||||
"pallet-authorship/std",
|
||||
"pallet-babe/std",
|
||||
@@ -228,6 +230,7 @@ runtime-benchmarks = [
|
||||
"frame-system-benchmarking/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
"hex-literal",
|
||||
"pallet-asset-rate/runtime-benchmarks",
|
||||
"pallet-babe/runtime-benchmarks",
|
||||
"pallet-bags-list/runtime-benchmarks",
|
||||
"pallet-balances/runtime-benchmarks",
|
||||
@@ -283,6 +286,7 @@ try-runtime = [
|
||||
"frame-system/try-runtime",
|
||||
"frame-try-runtime",
|
||||
"frame-try-runtime/try-runtime",
|
||||
"pallet-asset-rate/try-runtime",
|
||||
"pallet-authority-discovery/try-runtime",
|
||||
"pallet-authorship/try-runtime",
|
||||
"pallet-babe/try-runtime",
|
||||
|
||||
@@ -53,9 +53,14 @@ use primitives::{
|
||||
ValidatorSignature, PARACHAIN_KEY_TYPE_ID,
|
||||
};
|
||||
use runtime_common::{
|
||||
assigned_slots, auctions, crowdloan, elections::OnChainAccuracy, impl_runtime_weights,
|
||||
impls::ToAuthor, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BalanceToU256,
|
||||
BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance,
|
||||
assigned_slots, auctions, crowdloan,
|
||||
elections::OnChainAccuracy,
|
||||
impl_runtime_weights,
|
||||
impls::{
|
||||
LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedMultiLocationConverter,
|
||||
},
|
||||
paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BalanceToU256, BlockHashCount,
|
||||
BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance,
|
||||
};
|
||||
use runtime_parachains::{
|
||||
assigner_parachains as parachains_assigner_parachains,
|
||||
@@ -77,7 +82,7 @@ use sp_runtime::{
|
||||
generic, impl_opaque_keys,
|
||||
traits::{
|
||||
AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT,
|
||||
Keccak256, OpaqueKeys, SaturatedConversion, Verify,
|
||||
IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify,
|
||||
},
|
||||
transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
|
||||
ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill,
|
||||
@@ -87,7 +92,11 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||
#[cfg(any(feature = "std", test))]
|
||||
use sp_version::NativeVersion;
|
||||
use sp_version::RuntimeVersion;
|
||||
use xcm::latest::Junction;
|
||||
use xcm::{
|
||||
latest::{InteriorMultiLocation, Junction, Junction::PalletInstance},
|
||||
VersionedMultiLocation,
|
||||
};
|
||||
use xcm_builder::PayOverXcm;
|
||||
|
||||
pub use frame_system::Call as SystemCall;
|
||||
pub use pallet_balances::Call as BalancesCall;
|
||||
@@ -698,6 +707,10 @@ parameter_types! {
|
||||
pub const SpendPeriod: BlockNumber = 6 * DAYS;
|
||||
pub const Burn: Permill = Permill::from_perthousand(2);
|
||||
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
|
||||
pub const PayoutSpendPeriod: BlockNumber = 30 * DAYS;
|
||||
// The asset's interior location for the paying account. This is the Treasury
|
||||
// pallet instance (which sits at index 37).
|
||||
pub TreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(37).into();
|
||||
|
||||
pub const TipCountdown: BlockNumber = 1 * DAYS;
|
||||
pub const TipFindersFee: Percent = Percent::from_percent(20);
|
||||
@@ -707,6 +720,7 @@ parameter_types! {
|
||||
pub const MaxAuthorities: u32 = 100_000;
|
||||
pub const MaxKeys: u32 = 10_000;
|
||||
pub const MaxPeerInHeartbeats: u32 = 10_000;
|
||||
pub const MaxBalance: Balance = Balance::max_value();
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config for Runtime {
|
||||
@@ -726,6 +740,23 @@ impl pallet_treasury::Config for Runtime {
|
||||
type WeightInfo = weights::pallet_treasury::WeightInfo<Runtime>;
|
||||
type SpendFunds = ();
|
||||
type SpendOrigin = TreasurySpender;
|
||||
type AssetKind = VersionedLocatableAsset;
|
||||
type Beneficiary = VersionedMultiLocation;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = PayOverXcm<
|
||||
TreasuryInteriorLocation,
|
||||
crate::xcm_config::XcmRouter,
|
||||
crate::XcmPallet,
|
||||
ConstU32<{ 6 * HOURS }>,
|
||||
Self::Beneficiary,
|
||||
Self::AssetKind,
|
||||
LocatableAssetConverter,
|
||||
VersionedMultiLocationConverter,
|
||||
>;
|
||||
type BalanceConverter = AssetRate;
|
||||
type PayoutPeriod = PayoutSpendPeriod;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments;
|
||||
}
|
||||
|
||||
impl pallet_offences::Config for Runtime {
|
||||
@@ -1331,6 +1362,18 @@ parameter_types! {
|
||||
pub const MigrationMaxKeyLen: u32 = 512;
|
||||
}
|
||||
|
||||
impl pallet_asset_rate::Config for Runtime {
|
||||
type WeightInfo = weights::pallet_asset_rate::WeightInfo<Runtime>;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type CreateOrigin = EnsureRoot<AccountId>;
|
||||
type RemoveOrigin = EnsureRoot<AccountId>;
|
||||
type UpdateOrigin = EnsureRoot<AccountId>;
|
||||
type Currency = Balances;
|
||||
type AssetKind = <Runtime as pallet_treasury::Config>::AssetKind;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments;
|
||||
}
|
||||
|
||||
construct_runtime! {
|
||||
pub enum Runtime
|
||||
{
|
||||
@@ -1443,6 +1486,9 @@ construct_runtime! {
|
||||
|
||||
// Generalized message queue
|
||||
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 100,
|
||||
|
||||
// Asset rate.
|
||||
AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event<T>} = 101,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1574,6 +1620,7 @@ mod benches {
|
||||
[pallet_utility, Utility]
|
||||
[pallet_vesting, Vesting]
|
||||
[pallet_whitelist, Whitelist]
|
||||
[pallet_asset_rate, AssetRate]
|
||||
// XCM
|
||||
[pallet_xcm, XcmPallet]
|
||||
// NOTE: Make sure you point to the individual modules below.
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
pub mod frame_election_provider_support;
|
||||
pub mod frame_system;
|
||||
pub mod pallet_asset_rate;
|
||||
pub mod pallet_bags_list;
|
||||
pub mod pallet_balances;
|
||||
pub mod pallet_conviction_voting;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot 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.
|
||||
|
||||
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Autogenerated weights for `pallet_asset_rate`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-07-04, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `cob`, CPU: `<UNKNOWN>`
|
||||
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/debug/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=polkadot-dev
|
||||
// --steps=50
|
||||
// --repeat=2
|
||||
// --pallet=pallet_asset_rate
|
||||
// --extrinsic=*
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./runtime/polkadot/src/weights/
|
||||
// --header=./file_header.txt
|
||||
|
||||
#![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<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_asset_rate::WeightInfo for WeightInfo<T> {
|
||||
/// Storage: AssetRate ConversionRateToNative (r:1 w:1)
|
||||
/// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen)
|
||||
fn create() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 67_000_000 picoseconds.
|
||||
Weight::from_parts(69_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.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(1237), added: 3712, mode: MaxEncodedLen)
|
||||
fn update() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `110`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 69_000_000 picoseconds.
|
||||
Weight::from_parts(71_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.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(1237), added: 3712, mode: MaxEncodedLen)
|
||||
fn remove() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `110`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 70_000_000 picoseconds.
|
||||
Weight::from_parts(90_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.saturating_add(T::DbWeight::get().reads(1))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
}
|
||||
@@ -17,25 +17,24 @@
|
||||
//! Autogenerated weights for `pallet_treasury`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-07-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2023-07-07, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `runner-o7yfgx5n-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
|
||||
//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
|
||||
//! HOSTNAME: `cob`, CPU: `<UNKNOWN>`
|
||||
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// target/production/polkadot
|
||||
// ./target/debug/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=rococo-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --repeat=2
|
||||
// --pallet=pallet_treasury
|
||||
// --extrinsic=*
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=pallet_treasury
|
||||
// --chain=westend-dev
|
||||
// --output=./runtime/rococo/src/weights/
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/westend/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -48,103 +47,177 @@ use core::marker::PhantomData;
|
||||
/// Weight functions for `pallet_treasury`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_treasury::WeightInfo for WeightInfo<T> {
|
||||
/// Storage: `Treasury::ProposalCount` (r:1 w:1)
|
||||
/// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Treasury::Approvals` (r:1 w:1)
|
||||
/// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Treasury::Proposals` (r:0 w:1)
|
||||
/// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`)
|
||||
fn spend() -> Weight {
|
||||
/// Storage: Treasury ProposalCount (r:1 w:1)
|
||||
/// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:0 w:1)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
fn spend_local() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `6`
|
||||
// Measured: `42`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 13_644_000 picoseconds.
|
||||
Weight::from_parts(13_988_000, 0)
|
||||
// Minimum execution time: 177_000_000 picoseconds.
|
||||
Weight::from_parts(191_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: `Treasury::ProposalCount` (r:1 w:1)
|
||||
/// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Treasury::Proposals` (r:0 w:1)
|
||||
/// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`)
|
||||
/// Storage: Treasury ProposalCount (r:1 w:1)
|
||||
/// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:0 w:1)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
fn propose_spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `107`
|
||||
// Measured: `143`
|
||||
// Estimated: `1489`
|
||||
// Minimum execution time: 26_304_000 picoseconds.
|
||||
Weight::from_parts(26_850_000, 0)
|
||||
// Minimum execution time: 354_000_000 picoseconds.
|
||||
Weight::from_parts(376_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: `Treasury::Proposals` (r:1 w:1)
|
||||
/// Proof: `Treasury::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`)
|
||||
/// Storage: Treasury Proposals (r:1 w:1)
|
||||
/// Proof: Treasury 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: `265`
|
||||
// Measured: `301`
|
||||
// Estimated: `3593`
|
||||
// Minimum execution time: 40_318_000 picoseconds.
|
||||
Weight::from_parts(41_598_000, 0)
|
||||
// Minimum execution time: 547_000_000 picoseconds.
|
||||
Weight::from_parts(550_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3593))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
/// Storage: `Treasury::Proposals` (r:1 w:0)
|
||||
/// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Treasury::Approvals` (r:1 w:1)
|
||||
/// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`)
|
||||
/// Storage: Treasury Proposals (r:1 w:0)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn approve_proposal(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `433 + p * (8 ±0)`
|
||||
// Measured: `470 + p * (8 ±0)`
|
||||
// Estimated: `3573`
|
||||
// Minimum execution time: 8_250_000 picoseconds.
|
||||
Weight::from_parts(10_937_873, 0)
|
||||
// Minimum execution time: 104_000_000 picoseconds.
|
||||
Weight::from_parts(121_184_402, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3573))
|
||||
// Standard Error: 1_239
|
||||
.saturating_add(Weight::from_parts(82_426, 0).saturating_mul(p.into()))
|
||||
// Standard Error: 42_854
|
||||
.saturating_add(Weight::from_parts(153_112, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
/// Storage: `Treasury::Approvals` (r:1 w:1)
|
||||
/// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`)
|
||||
/// Storage: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
fn remove_approval() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `90`
|
||||
// Measured: `127`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 6_170_000 picoseconds.
|
||||
Weight::from_parts(6_366_000, 0)
|
||||
// Minimum execution time: 80_000_000 picoseconds.
|
||||
Weight::from_parts(82_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: `Treasury::Deactivated` (r:1 w:1)
|
||||
/// Proof: `Treasury::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: `Treasury::Approvals` (r:1 w:1)
|
||||
/// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Treasury::Proposals` (r:100 w:100)
|
||||
/// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:200 w:200)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `p` is `[0, 100]`.
|
||||
/// Storage: Treasury Deactivated (r:1 w:1)
|
||||
/// Proof: Treasury 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: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:99 w:99)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
/// Storage: System Account (r:199 w:199)
|
||||
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
|
||||
/// Storage: Bounties BountyApprovals (r:1 w:1)
|
||||
/// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn on_initialize_proposals(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `175 + p * (251 ±0)`
|
||||
// Estimated: `1887 + p * (5206 ±0)`
|
||||
// Minimum execution time: 39_691_000 picoseconds.
|
||||
Weight::from_parts(29_703_313, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1887))
|
||||
// Standard Error: 18_540
|
||||
.saturating_add(Weight::from_parts(42_601_290, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(3))
|
||||
// Measured: `331 + p * (251 ±0)`
|
||||
// Estimated: `3593 + p * (5206 ±0)`
|
||||
// Minimum execution time: 887_000_000 picoseconds.
|
||||
Weight::from_parts(828_616_021, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3593))
|
||||
// Standard Error: 695_351
|
||||
.saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.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(5))
|
||||
.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(1237), added: 3712, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury SpendCount (r:1 w:1)
|
||||
/// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Spends (r:0 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
fn spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `114`
|
||||
// Estimated: `4702`
|
||||
// Minimum execution time: 208_000_000 picoseconds.
|
||||
Weight::from_parts(222_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4702))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
/// Storage: XcmPallet QueryCounter (r:1 w:1)
|
||||
/// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
|
||||
/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: XcmPallet Queries (r:0 w:1)
|
||||
/// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured)
|
||||
fn payout() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `737`
|
||||
// Estimated: `5313`
|
||||
// Minimum execution time: 551_000_000 picoseconds.
|
||||
Weight::from_parts(569_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 5313))
|
||||
.saturating_add(T::DbWeight::get().reads(9))
|
||||
.saturating_add(T::DbWeight::get().writes(6))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
/// Storage: XcmPallet Queries (r:1 w:1)
|
||||
/// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured)
|
||||
fn check_status() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `442`
|
||||
// Estimated: `5313`
|
||||
// Minimum execution time: 245_000_000 picoseconds.
|
||||
Weight::from_parts(281_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 5313))
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen)
|
||||
fn void_spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `172`
|
||||
// Estimated: `5313`
|
||||
// Minimum execution time: 147_000_000 picoseconds.
|
||||
Weight::from_parts(160_000_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 5313))
|
||||
.saturating_add(T::DbWeight::get().reads(1))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ use frame_support::{
|
||||
parameter_types,
|
||||
traits::{
|
||||
fungible::{Balanced, Credit, HoldConsideration, ItemOf},
|
||||
tokens::{nonfungibles_v2::Inspect, GetSalary, PayFromAccount},
|
||||
tokens::{nonfungibles_v2::Inspect, pay::PayAssetFromAccount, GetSalary, PayFromAccount},
|
||||
AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Contains, Currency,
|
||||
EitherOfDiverse, EqualPrivilegeOnly, Imbalance, InsideBoth, InstanceFilter,
|
||||
KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, OnUnbalanced,
|
||||
@@ -1186,6 +1186,7 @@ parameter_types! {
|
||||
pub const MaximumReasonLength: u32 = 300;
|
||||
pub const MaxApprovals: u32 = 100;
|
||||
pub const MaxBalance: Balance = Balance::max_value();
|
||||
pub const SpendPayoutPeriod: BlockNumber = 30 * DAYS;
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config for Runtime {
|
||||
@@ -1211,6 +1212,14 @@ impl pallet_treasury::Config for Runtime {
|
||||
type WeightInfo = pallet_treasury::weights::SubstrateWeight<Runtime>;
|
||||
type MaxApprovals = MaxApprovals;
|
||||
type SpendOrigin = EnsureWithSuccess<EnsureRoot<AccountId>, AccountId, MaxBalance>;
|
||||
type AssetKind = u32;
|
||||
type Beneficiary = AccountId;
|
||||
type BeneficiaryLookup = Indices;
|
||||
type Paymaster = PayAssetFromAccount<Assets, TreasuryAccount>;
|
||||
type BalanceConverter = AssetRate;
|
||||
type PayoutPeriod = SpendPayoutPeriod;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
impl pallet_asset_rate::Config for Runtime {
|
||||
|
||||
@@ -240,4 +240,9 @@ where
|
||||
.ok_or(pallet::Error::<T>::UnknownAssetKind.into())?;
|
||||
Ok(rate.saturating_mul_int(balance))
|
||||
}
|
||||
/// Set a conversion rate to `1` for the `asset_id`.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_successful(asset_id: AssetKindOf<T>) {
|
||||
pallet::ConversionRateToNative::<T>::set(asset_id.clone(), Some(1.into()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ use crate as pallet_bounties;
|
||||
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, parameter_types,
|
||||
traits::{ConstU32, ConstU64, OnInitialize},
|
||||
traits::{
|
||||
tokens::{PayFromAccount, UnityAssetBalanceConversion},
|
||||
ConstU32, ConstU64, OnInitialize,
|
||||
},
|
||||
PalletId,
|
||||
};
|
||||
|
||||
@@ -104,6 +107,8 @@ parameter_types! {
|
||||
pub const TreasuryPalletId2: PalletId = PalletId(*b"py/trsr2");
|
||||
pub static SpendLimit: Balance = u64::MAX;
|
||||
pub static SpendLimit1: Balance = u64::MAX;
|
||||
pub TreasuryAccount: u128 = Treasury::account_id();
|
||||
pub TreasuryInstance1Account: u128 = Treasury1::account_id();
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config for Test {
|
||||
@@ -123,6 +128,14 @@ impl pallet_treasury::Config for Test {
|
||||
type SpendFunds = Bounties;
|
||||
type MaxApprovals = ConstU32<100>;
|
||||
type SpendOrigin = frame_system::EnsureRootWithSuccess<Self::AccountId, SpendLimit>;
|
||||
type AssetKind = ();
|
||||
type Beneficiary = Self::AccountId;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = PayFromAccount<Balances, TreasuryAccount>;
|
||||
type BalanceConverter = UnityAssetBalanceConversion;
|
||||
type PayoutPeriod = ConstU64<10>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config<Instance1> for Test {
|
||||
@@ -142,6 +155,14 @@ impl pallet_treasury::Config<Instance1> for Test {
|
||||
type SpendFunds = Bounties1;
|
||||
type MaxApprovals = ConstU32<100>;
|
||||
type SpendOrigin = frame_system::EnsureRootWithSuccess<Self::AccountId, SpendLimit1>;
|
||||
type AssetKind = ();
|
||||
type Beneficiary = Self::AccountId;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = PayFromAccount<Balances, TreasuryInstance1Account>;
|
||||
type BalanceConverter = UnityAssetBalanceConversion;
|
||||
type PayoutPeriod = ConstU64<10>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
|
||||
@@ -24,7 +24,10 @@ use crate as pallet_child_bounties;
|
||||
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, parameter_types,
|
||||
traits::{ConstU32, ConstU64, OnInitialize},
|
||||
traits::{
|
||||
tokens::{PayFromAccount, UnityAssetBalanceConversion},
|
||||
ConstU32, ConstU64, OnInitialize,
|
||||
},
|
||||
weights::Weight,
|
||||
PalletId,
|
||||
};
|
||||
@@ -104,6 +107,7 @@ parameter_types! {
|
||||
pub const ProposalBond: Permill = Permill::from_percent(5);
|
||||
pub const Burn: Permill = Permill::from_percent(50);
|
||||
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
|
||||
pub TreasuryAccount: u128 = Treasury::account_id();
|
||||
pub const SpendLimit: Balance = u64::MAX;
|
||||
}
|
||||
|
||||
@@ -124,6 +128,14 @@ impl pallet_treasury::Config for Test {
|
||||
type SpendFunds = Bounties;
|
||||
type MaxApprovals = ConstU32<100>;
|
||||
type SpendOrigin = frame_system::EnsureRootWithSuccess<Self::AccountId, SpendLimit>;
|
||||
type AssetKind = ();
|
||||
type Beneficiary = Self::AccountId;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = PayFromAccount<Balances, TreasuryAccount>;
|
||||
type BalanceConverter = UnityAssetBalanceConversion;
|
||||
type PayoutPeriod = ConstU64<10>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
parameter_types! {
|
||||
// This will be 50% of the bounty fee.
|
||||
|
||||
@@ -31,6 +31,7 @@ pub mod pay;
|
||||
pub use misc::{
|
||||
AssetId, Balance, BalanceStatus, ConversionFromAssetBalance, ConversionToAssetBalance,
|
||||
ConvertRank, DepositConsequence, ExistenceRequirement, Fortitude, GetSalary, Locker, Precision,
|
||||
Preservation, Provenance, Restriction, WithdrawConsequence, WithdrawReasons,
|
||||
Preservation, Provenance, Restriction, UnityAssetBalanceConversion, WithdrawConsequence,
|
||||
WithdrawReasons,
|
||||
};
|
||||
pub use pay::{Pay, PayFromAccount, PaymentStatus};
|
||||
|
||||
@@ -277,6 +277,26 @@ pub trait ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance> {
|
||||
balance: AssetBalance,
|
||||
asset_id: AssetId,
|
||||
) -> Result<OutBalance, Self::Error>;
|
||||
/// Ensures that a conversion for the `asset_id` will be successful if done immediately after
|
||||
/// this call.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_successful(asset_id: AssetId);
|
||||
}
|
||||
|
||||
/// Implements [`ConversionFromAssetBalance`], enabling a 1:1 conversion of the asset balance
|
||||
/// value to the balance.
|
||||
pub struct UnityAssetBalanceConversion;
|
||||
impl<AssetBalance, AssetId, OutBalance>
|
||||
ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance> for UnityAssetBalanceConversion
|
||||
where
|
||||
AssetBalance: Into<OutBalance>,
|
||||
{
|
||||
type Error = ();
|
||||
fn from_asset_balance(balance: AssetBalance, _: AssetId) -> Result<OutBalance, Self::Error> {
|
||||
Ok(balance.into())
|
||||
}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_successful(_: AssetId) {}
|
||||
}
|
||||
|
||||
/// Trait to handle NFT locking mechanism to ensure interactions with the asset can be implemented
|
||||
|
||||
@@ -23,7 +23,7 @@ use sp_core::{RuntimeDebug, TypedGet};
|
||||
use sp_runtime::DispatchError;
|
||||
use sp_std::fmt::Debug;
|
||||
|
||||
use super::{fungible, Balance, Preservation::Expendable};
|
||||
use super::{fungible, fungibles, Balance, Preservation::Expendable};
|
||||
|
||||
/// Can be implemented by `PayFromAccount` using a `fungible` impl, but can also be implemented with
|
||||
/// XCM/MultiAsset and made generic over assets.
|
||||
@@ -107,3 +107,36 @@ impl<A: TypedGet, F: fungible::Mutate<A::Type>> Pay for PayFromAccount<F, A> {
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_concluded(_: Self::Id) {}
|
||||
}
|
||||
|
||||
/// Simple implementation of `Pay` for assets which makes a payment from a "pot" - i.e. a single
|
||||
/// account.
|
||||
pub struct PayAssetFromAccount<F, A>(sp_std::marker::PhantomData<(F, A)>);
|
||||
impl<A, F> frame_support::traits::tokens::Pay for PayAssetFromAccount<F, A>
|
||||
where
|
||||
A: TypedGet,
|
||||
F: fungibles::Mutate<A::Type> + fungibles::Create<A::Type>,
|
||||
{
|
||||
type Balance = F::Balance;
|
||||
type Beneficiary = A::Type;
|
||||
type AssetKind = F::AssetId;
|
||||
type Id = ();
|
||||
type Error = DispatchError;
|
||||
fn pay(
|
||||
who: &Self::Beneficiary,
|
||||
asset: Self::AssetKind,
|
||||
amount: Self::Balance,
|
||||
) -> Result<Self::Id, Self::Error> {
|
||||
<F as fungibles::Mutate<_>>::transfer(asset, &A::get(), who, amount, Expendable)?;
|
||||
Ok(())
|
||||
}
|
||||
fn check_payment(_: ()) -> PaymentStatus {
|
||||
PaymentStatus::Success
|
||||
}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_successful(_: &Self::Beneficiary, asset: Self::AssetKind, amount: Self::Balance) {
|
||||
<F as fungibles::Create<_>>::create(asset.clone(), A::get(), true, amount).unwrap();
|
||||
<F as fungibles::Mutate<_>>::mint_into(asset, &A::get(), amount).unwrap();
|
||||
}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_concluded(_: Self::Id) {}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ use sp_storage::Storage;
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, parameter_types,
|
||||
storage::StoragePrefixedMap,
|
||||
traits::{ConstU32, ConstU64, SortedMembers, StorageVersion},
|
||||
traits::{
|
||||
tokens::{PayFromAccount, UnityAssetBalanceConversion},
|
||||
ConstU32, ConstU64, SortedMembers, StorageVersion,
|
||||
},
|
||||
PalletId,
|
||||
};
|
||||
|
||||
@@ -123,7 +126,10 @@ parameter_types! {
|
||||
pub const Burn: Permill = Permill::from_percent(50);
|
||||
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
|
||||
pub const TreasuryPalletId2: PalletId = PalletId(*b"py/trsr2");
|
||||
pub TreasuryAccount: u128 = Treasury::account_id();
|
||||
pub TreasuryInstance1Account: u128 = Treasury1::account_id();
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config for Test {
|
||||
type PalletId = TreasuryPalletId;
|
||||
type Currency = pallet_balances::Pallet<Test>;
|
||||
@@ -141,6 +147,14 @@ impl pallet_treasury::Config for Test {
|
||||
type SpendFunds = ();
|
||||
type MaxApprovals = ConstU32<100>;
|
||||
type SpendOrigin = frame_support::traits::NeverEnsureOrigin<u64>;
|
||||
type AssetKind = ();
|
||||
type Beneficiary = Self::AccountId;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = PayFromAccount<Balances, TreasuryAccount>;
|
||||
type BalanceConverter = UnityAssetBalanceConversion;
|
||||
type PayoutPeriod = ConstU64<10>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
impl pallet_treasury::Config<Instance1> for Test {
|
||||
@@ -160,6 +174,14 @@ impl pallet_treasury::Config<Instance1> for Test {
|
||||
type SpendFunds = ();
|
||||
type MaxApprovals = ConstU32<100>;
|
||||
type SpendOrigin = frame_support::traits::NeverEnsureOrigin<u64>;
|
||||
type AssetKind = ();
|
||||
type Beneficiary = Self::AccountId;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = PayFromAccount<Balances, TreasuryInstance1Account>;
|
||||
type BalanceConverter = UnityAssetBalanceConversion;
|
||||
type PayoutPeriod = ConstU64<10>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
|
||||
@@ -17,6 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features =
|
||||
"derive",
|
||||
"max-encoded-len",
|
||||
] }
|
||||
docify = "0.2.0"
|
||||
impl-trait-for-tuples = "0.2.2"
|
||||
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.188", features = ["derive"], optional = true }
|
||||
@@ -26,11 +27,12 @@ frame-system = { path = "../system", default-features = false}
|
||||
pallet-balances = { path = "../balances", default-features = false}
|
||||
sp-runtime = { path = "../../primitives/runtime", default-features = false}
|
||||
sp-std = { path = "../../primitives/std", default-features = false}
|
||||
sp-core = { path = "../../primitives/core", default-features = false, optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
sp-core = { path = "../../primitives/core" }
|
||||
sp-io = { path = "../../primitives/io" }
|
||||
pallet-utility = { path = "../utility" }
|
||||
sp-core = { path = "../../primitives/core", default-features = false }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
@@ -43,12 +45,13 @@ std = [
|
||||
"pallet-utility/std",
|
||||
"scale-info/std",
|
||||
"serde",
|
||||
"sp-core/std",
|
||||
"sp-core?/std",
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"dep:sp-core",
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
|
||||
@@ -21,12 +21,41 @@
|
||||
|
||||
use super::{Pallet as Treasury, *};
|
||||
|
||||
use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError};
|
||||
use frame_benchmarking::{
|
||||
v1::{account, BenchmarkError},
|
||||
v2::*,
|
||||
};
|
||||
use frame_support::{
|
||||
ensure,
|
||||
traits::{EnsureOrigin, OnInitialize, UnfilteredDispatchable},
|
||||
traits::{
|
||||
tokens::{ConversionFromAssetBalance, PaymentStatus},
|
||||
EnsureOrigin, OnInitialize,
|
||||
},
|
||||
};
|
||||
use frame_system::RawOrigin;
|
||||
use sp_core::crypto::FromEntropy;
|
||||
|
||||
/// Trait describing factory functions for dispatchables' parameters.
|
||||
pub trait ArgumentsFactory<AssetKind, Beneficiary> {
|
||||
/// Factory function for an asset kind.
|
||||
fn create_asset_kind(seed: u32) -> AssetKind;
|
||||
/// Factory function for a beneficiary.
|
||||
fn create_beneficiary(seed: [u8; 32]) -> Beneficiary;
|
||||
}
|
||||
|
||||
/// Implementation that expects the parameters implement the [`FromEntropy`] trait.
|
||||
impl<AssetKind, Beneficiary> ArgumentsFactory<AssetKind, Beneficiary> for ()
|
||||
where
|
||||
AssetKind: FromEntropy,
|
||||
Beneficiary: FromEntropy,
|
||||
{
|
||||
fn create_asset_kind(seed: u32) -> AssetKind {
|
||||
AssetKind::from_entropy(&mut seed.encode().as_slice()).unwrap()
|
||||
}
|
||||
fn create_beneficiary(seed: [u8; 32]) -> Beneficiary {
|
||||
Beneficiary::from_entropy(&mut seed.as_slice()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
@@ -66,81 +95,245 @@ fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::
|
||||
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
|
||||
}
|
||||
|
||||
benchmarks_instance_pallet! {
|
||||
// Create the arguments for the `spend` dispatchable.
|
||||
fn create_spend_arguments<T: Config<I>, I: 'static>(
|
||||
seed: u32,
|
||||
) -> (T::AssetKind, AssetBalanceOf<T, I>, T::Beneficiary, BeneficiaryLookupOf<T, I>) {
|
||||
let asset_kind = T::BenchmarkHelper::create_asset_kind(seed);
|
||||
let beneficiary = T::BenchmarkHelper::create_beneficiary([seed.try_into().unwrap(); 32]);
|
||||
let beneficiary_lookup = T::BeneficiaryLookup::unlookup(beneficiary.clone());
|
||||
(asset_kind, 100u32.into(), beneficiary, beneficiary_lookup)
|
||||
}
|
||||
|
||||
#[instance_benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
// This benchmark is short-circuited if `SpendOrigin` cannot provide
|
||||
// a successful origin, in which case `spend` is un-callable and can use weight=0.
|
||||
spend {
|
||||
#[benchmark]
|
||||
fn spend_local() -> Result<(), BenchmarkError> {
|
||||
let (_, value, beneficiary_lookup) = setup_proposal::<T, _>(SEED);
|
||||
let origin = T::SpendOrigin::try_successful_origin();
|
||||
let origin =
|
||||
T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
let beneficiary = T::Lookup::lookup(beneficiary_lookup.clone()).unwrap();
|
||||
let call = Call::<T, I>::spend { amount: value, beneficiary: beneficiary_lookup };
|
||||
}: {
|
||||
if let Ok(origin) = origin.clone() {
|
||||
call.dispatch_bypass_filter(origin)?;
|
||||
}
|
||||
}
|
||||
verify {
|
||||
if origin.is_ok() {
|
||||
assert_last_event::<T, I>(Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into())
|
||||
}
|
||||
|
||||
#[extrinsic_call]
|
||||
_(origin as T::RuntimeOrigin, value, beneficiary_lookup);
|
||||
|
||||
assert_last_event::<T, I>(
|
||||
Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
propose_spend {
|
||||
#[benchmark]
|
||||
fn propose_spend() -> Result<(), BenchmarkError> {
|
||||
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(SEED);
|
||||
// Whitelist caller account from further DB operations.
|
||||
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
|
||||
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
|
||||
}: _(RawOrigin::Signed(caller), value, beneficiary_lookup)
|
||||
|
||||
reject_proposal {
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller), value, beneficiary_lookup);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn reject_proposal() -> Result<(), BenchmarkError> {
|
||||
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(SEED);
|
||||
#[allow(deprecated)]
|
||||
Treasury::<T, _>::propose_spend(
|
||||
RawOrigin::Signed(caller).into(),
|
||||
value,
|
||||
beneficiary_lookup
|
||||
beneficiary_lookup,
|
||||
)?;
|
||||
let proposal_id = Treasury::<T, _>::proposal_count() - 1;
|
||||
let reject_origin =
|
||||
T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
}: _<T::RuntimeOrigin>(reject_origin, proposal_id)
|
||||
|
||||
approve_proposal {
|
||||
let p in 0 .. T::MaxApprovals::get() - 1;
|
||||
#[extrinsic_call]
|
||||
_(reject_origin as T::RuntimeOrigin, proposal_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn approve_proposal(
|
||||
p: Linear<0, { T::MaxApprovals::get() - 1 }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
create_approved_proposals::<T, _>(p)?;
|
||||
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(SEED);
|
||||
#[allow(deprecated)]
|
||||
Treasury::<T, _>::propose_spend(
|
||||
RawOrigin::Signed(caller).into(),
|
||||
value,
|
||||
beneficiary_lookup
|
||||
beneficiary_lookup,
|
||||
)?;
|
||||
let proposal_id = Treasury::<T, _>::proposal_count() - 1;
|
||||
let approve_origin =
|
||||
T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
}: _<T::RuntimeOrigin>(approve_origin, proposal_id)
|
||||
|
||||
remove_approval {
|
||||
#[extrinsic_call]
|
||||
_(approve_origin as T::RuntimeOrigin, proposal_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn remove_approval() -> Result<(), BenchmarkError> {
|
||||
let (caller, value, beneficiary_lookup) = setup_proposal::<T, _>(SEED);
|
||||
#[allow(deprecated)]
|
||||
Treasury::<T, _>::propose_spend(
|
||||
RawOrigin::Signed(caller).into(),
|
||||
value,
|
||||
beneficiary_lookup
|
||||
beneficiary_lookup,
|
||||
)?;
|
||||
let proposal_id = Treasury::<T, _>::proposal_count() - 1;
|
||||
#[allow(deprecated)]
|
||||
Treasury::<T, I>::approve_proposal(RawOrigin::Root.into(), proposal_id)?;
|
||||
let reject_origin =
|
||||
T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
}: _<T::RuntimeOrigin>(reject_origin, proposal_id)
|
||||
|
||||
on_initialize_proposals {
|
||||
let p in 0 .. T::MaxApprovals::get();
|
||||
#[extrinsic_call]
|
||||
_(reject_origin as T::RuntimeOrigin, proposal_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn on_initialize_proposals(
|
||||
p: Linear<0, { T::MaxApprovals::get() - 1 }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
setup_pot_account::<T, _>();
|
||||
create_approved_proposals::<T, _>(p)?;
|
||||
}: {
|
||||
Treasury::<T, _>::on_initialize(frame_system::pallet_prelude::BlockNumberFor::<T>::zero());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Treasury::<T, _>::on_initialize(0u32.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn spend() -> Result<(), BenchmarkError> {
|
||||
let origin =
|
||||
T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
let (asset_kind, amount, beneficiary, beneficiary_lookup) =
|
||||
create_spend_arguments::<T, _>(SEED);
|
||||
T::BalanceConverter::ensure_successful(asset_kind.clone());
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
origin as T::RuntimeOrigin,
|
||||
Box::new(asset_kind.clone()),
|
||||
amount,
|
||||
Box::new(beneficiary_lookup),
|
||||
None,
|
||||
);
|
||||
|
||||
let valid_from = frame_system::Pallet::<T>::block_number();
|
||||
let expire_at = valid_from.saturating_add(T::PayoutPeriod::get());
|
||||
assert_last_event::<T, I>(
|
||||
Event::AssetSpendApproved {
|
||||
index: 0,
|
||||
asset_kind,
|
||||
amount,
|
||||
beneficiary,
|
||||
valid_from,
|
||||
expire_at,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn payout() -> Result<(), BenchmarkError> {
|
||||
let origin = T::SpendOrigin::try_successful_origin().map_err(|_| "No origin")?;
|
||||
let (asset_kind, amount, beneficiary, beneficiary_lookup) =
|
||||
create_spend_arguments::<T, _>(SEED);
|
||||
T::BalanceConverter::ensure_successful(asset_kind.clone());
|
||||
Treasury::<T, _>::spend(
|
||||
origin,
|
||||
Box::new(asset_kind.clone()),
|
||||
amount,
|
||||
Box::new(beneficiary_lookup),
|
||||
None,
|
||||
)?;
|
||||
T::Paymaster::ensure_successful(&beneficiary, asset_kind, amount);
|
||||
let caller: T::AccountId = account("caller", 0, SEED);
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller.clone()), 0u32);
|
||||
|
||||
let id = match Spends::<T, I>::get(0).unwrap().status {
|
||||
PaymentState::Attempted { id, .. } => {
|
||||
assert_ne!(T::Paymaster::check_payment(id), PaymentStatus::Failure);
|
||||
id
|
||||
},
|
||||
_ => panic!("No payout attempt made"),
|
||||
};
|
||||
assert_last_event::<T, I>(Event::Paid { index: 0, payment_id: id }.into());
|
||||
assert!(Treasury::<T, _>::payout(RawOrigin::Signed(caller).into(), 0u32).is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn check_status() -> Result<(), BenchmarkError> {
|
||||
let origin = T::SpendOrigin::try_successful_origin().map_err(|_| "No origin")?;
|
||||
let (asset_kind, amount, beneficiary, beneficiary_lookup) =
|
||||
create_spend_arguments::<T, _>(SEED);
|
||||
T::BalanceConverter::ensure_successful(asset_kind.clone());
|
||||
Treasury::<T, _>::spend(
|
||||
origin,
|
||||
Box::new(asset_kind.clone()),
|
||||
amount,
|
||||
Box::new(beneficiary_lookup),
|
||||
None,
|
||||
)?;
|
||||
T::Paymaster::ensure_successful(&beneficiary, asset_kind, amount);
|
||||
let caller: T::AccountId = account("caller", 0, SEED);
|
||||
Treasury::<T, _>::payout(RawOrigin::Signed(caller.clone()).into(), 0u32)?;
|
||||
match Spends::<T, I>::get(0).unwrap().status {
|
||||
PaymentState::Attempted { id, .. } => {
|
||||
T::Paymaster::ensure_concluded(id);
|
||||
},
|
||||
_ => panic!("No payout attempt made"),
|
||||
};
|
||||
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Signed(caller.clone()), 0u32);
|
||||
|
||||
if let Some(s) = Spends::<T, I>::get(0) {
|
||||
assert!(!matches!(s.status, PaymentState::Attempted { .. }));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn void_spend() -> Result<(), BenchmarkError> {
|
||||
let origin = T::SpendOrigin::try_successful_origin().map_err(|_| "No origin")?;
|
||||
let (asset_kind, amount, _, beneficiary_lookup) = create_spend_arguments::<T, _>(SEED);
|
||||
T::BalanceConverter::ensure_successful(asset_kind.clone());
|
||||
Treasury::<T, _>::spend(
|
||||
origin,
|
||||
Box::new(asset_kind.clone()),
|
||||
amount,
|
||||
Box::new(beneficiary_lookup),
|
||||
None,
|
||||
)?;
|
||||
assert!(Spends::<T, I>::get(0).is_some());
|
||||
let origin =
|
||||
T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
|
||||
|
||||
#[extrinsic_call]
|
||||
_(origin as T::RuntimeOrigin, 0u32);
|
||||
|
||||
assert!(Spends::<T, I>::get(0).is_none());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(Treasury, crate::tests::new_test_ext(), crate::tests::Test);
|
||||
|
||||
@@ -15,46 +15,60 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! > Made with *Substrate*, for *Polkadot*.
|
||||
//!
|
||||
//! [![github]](https://github.com/paritytech/substrate/frame/fast-unstake) -
|
||||
//! [![polkadot]](https://polkadot.network)
|
||||
//!
|
||||
//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white
|
||||
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
|
||||
//!
|
||||
//! # Treasury Pallet
|
||||
//!
|
||||
//! The Treasury pallet provides a "pot" of funds that can be managed by stakeholders in the system
|
||||
//! and a structure for making spending proposals from this pot.
|
||||
//!
|
||||
//! - [`Config`]
|
||||
//! - [`Call`]
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! The Treasury Pallet itself provides the pot to store funds, and a means for stakeholders to
|
||||
//! propose, approve, and deny expenditures. The chain will need to provide a method (e.g.
|
||||
//! inflation, fees) for collecting funds.
|
||||
//! propose and claim expenditures (aka spends). The chain will need to provide a method to approve
|
||||
//! spends (e.g. public referendum) and a method for collecting funds (e.g. inflation, fees).
|
||||
//!
|
||||
//! By way of example, the Council could vote to fund the Treasury with a portion of the block
|
||||
//! By way of example, stakeholders could vote to fund the Treasury with a portion of the block
|
||||
//! reward and use the funds to pay developers.
|
||||
//!
|
||||
//!
|
||||
//! ### Terminology
|
||||
//!
|
||||
//! - **Proposal:** A suggestion to allocate funds from the pot to a beneficiary.
|
||||
//! - **Beneficiary:** An account who will receive the funds from a proposal iff the proposal is
|
||||
//! approved.
|
||||
//! - **Deposit:** Funds that a proposer must lock when making a proposal. The deposit will be
|
||||
//! returned or slashed if the proposal is approved or rejected respectively.
|
||||
//! - **Pot:** Unspent funds accumulated by the treasury pallet.
|
||||
//! - **Spend** An approved proposal for transferring a specific amount of funds to a designated
|
||||
//! beneficiary.
|
||||
//!
|
||||
//! ## Interface
|
||||
//! ### Example
|
||||
//!
|
||||
//! ### Dispatchable Functions
|
||||
//! 1. Multiple local spends approved by spend origins and received by a beneficiary.
|
||||
#![doc = docify::embed!("src/tests.rs", spend_local_origin_works)]
|
||||
//!
|
||||
//! General spending/proposal protocol:
|
||||
//! - `propose_spend` - Make a spending proposal and stake the required deposit.
|
||||
//! - `reject_proposal` - Reject a proposal, slashing the deposit.
|
||||
//! - `approve_proposal` - Accept the proposal, returning the deposit.
|
||||
//! - `remove_approval` - Remove an approval, the deposit will no longer be returned.
|
||||
//! 2. Approve a spend of some asset kind and claim it.
|
||||
#![doc = docify::embed!("src/tests.rs", spend_payout_works)]
|
||||
//!
|
||||
//! ## GenesisConfig
|
||||
//! ## Pallet API
|
||||
//!
|
||||
//! The Treasury pallet depends on the [`GenesisConfig`].
|
||||
//! See the [`pallet`] module for more information about the interfaces this pallet exposes,
|
||||
//! including its configuration trait, dispatchables, storage items, events and errors.
|
||||
//!
|
||||
//! ## Low Level / Implementation Details
|
||||
//!
|
||||
//! Spends can be initiated using either the `spend_local` or `spend` dispatchable. The
|
||||
//! `spend_local` dispatchable enables the creation of spends using the native currency of the
|
||||
//! chain, utilizing the funds stored in the pot. These spends are automatically paid out every
|
||||
//! [`pallet::Config::SpendPeriod`]. On the other hand, the `spend` dispatchable allows spending of
|
||||
//! any asset kind managed by the treasury, with payment facilitated by a designated
|
||||
//! [`pallet::Config::Paymaster`]. To claim these spends, the `payout` dispatchable should be called
|
||||
//! within some temporal bounds, starting from the moment they become valid and within one
|
||||
//! [`pallet::Config::PayoutPeriod`].
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
@@ -62,6 +76,8 @@ mod benchmarking;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub mod weights;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub use benchmarking::ArgumentsFactory;
|
||||
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
@@ -75,7 +91,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||
use frame_support::{
|
||||
print,
|
||||
traits::{
|
||||
Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced,
|
||||
tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced,
|
||||
ReservableCurrency, WithdrawReasons,
|
||||
},
|
||||
weights::Weight,
|
||||
@@ -87,6 +103,7 @@ pub use weights::WeightInfo;
|
||||
|
||||
pub type BalanceOf<T, I = ()> =
|
||||
<<T as Config<I>>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
|
||||
pub type AssetBalanceOf<T, I> = <<T as Config<I>>::Paymaster as Pay>::Balance;
|
||||
pub type PositiveImbalanceOf<T, I = ()> = <<T as Config<I>>::Currency as Currency<
|
||||
<T as frame_system::Config>::AccountId,
|
||||
>>::PositiveImbalance;
|
||||
@@ -94,6 +111,7 @@ pub type NegativeImbalanceOf<T, I = ()> = <<T as Config<I>>::Currency as Currenc
|
||||
<T as frame_system::Config>::AccountId,
|
||||
>>::NegativeImbalance;
|
||||
type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
|
||||
type BeneficiaryLookupOf<T, I> = <<T as Config<I>>::BeneficiaryLookup as StaticLookup>::Source;
|
||||
|
||||
/// A trait to allow the Treasury Pallet to spend it's funds for other purposes.
|
||||
/// There is an expectation that the implementer of this trait will correctly manage
|
||||
@@ -133,10 +151,47 @@ pub struct Proposal<AccountId, Balance> {
|
||||
bond: Balance,
|
||||
}
|
||||
|
||||
/// The state of the payment claim.
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, MaxEncodedLen, RuntimeDebug, TypeInfo)]
|
||||
pub enum PaymentState<Id> {
|
||||
/// Pending claim.
|
||||
Pending,
|
||||
/// Payment attempted with a payment identifier.
|
||||
Attempted { id: Id },
|
||||
/// Payment failed.
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Info regarding an approved treasury spend.
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, MaxEncodedLen, RuntimeDebug, TypeInfo)]
|
||||
pub struct SpendStatus<AssetKind, AssetBalance, Beneficiary, BlockNumber, PaymentId> {
|
||||
// The kind of asset to be spent.
|
||||
asset_kind: AssetKind,
|
||||
/// The asset amount of the spend.
|
||||
amount: AssetBalance,
|
||||
/// The beneficiary of the spend.
|
||||
beneficiary: Beneficiary,
|
||||
/// The block number from which the spend can be claimed.
|
||||
valid_from: BlockNumber,
|
||||
/// The block number by which the spend has to be claimed.
|
||||
expire_at: BlockNumber,
|
||||
/// The status of the payout/claim.
|
||||
status: PaymentState<PaymentId>,
|
||||
}
|
||||
|
||||
/// Index of an approved treasury spend.
|
||||
pub type SpendIndex = u32;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::{dispatch_context::with_context, pallet_prelude::*};
|
||||
use frame_support::{
|
||||
dispatch_context::with_context,
|
||||
pallet_prelude::*,
|
||||
traits::tokens::{ConversionFromAssetBalance, PaymentStatus},
|
||||
};
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
@@ -201,9 +256,38 @@ pub mod pallet {
|
||||
type MaxApprovals: Get<u32>;
|
||||
|
||||
/// The origin required for approving spends from the treasury outside of the proposal
|
||||
/// process. The `Success` value is the maximum amount that this origin is allowed to
|
||||
/// spend at a time.
|
||||
/// process. The `Success` value is the maximum amount in a native asset that this origin
|
||||
/// is allowed to spend at a time.
|
||||
type SpendOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = BalanceOf<Self, I>>;
|
||||
|
||||
/// Type parameter representing the asset kinds to be spent from the treasury.
|
||||
type AssetKind: Parameter + MaxEncodedLen;
|
||||
|
||||
/// Type parameter used to identify the beneficiaries eligible to receive treasury spends.
|
||||
type Beneficiary: Parameter + MaxEncodedLen;
|
||||
|
||||
/// Converting trait to take a source type and convert to [`Self::Beneficiary`].
|
||||
type BeneficiaryLookup: StaticLookup<Target = Self::Beneficiary>;
|
||||
|
||||
/// Type for processing spends of [Self::AssetKind] in favor of [`Self::Beneficiary`].
|
||||
type Paymaster: Pay<Beneficiary = Self::Beneficiary, AssetKind = Self::AssetKind>;
|
||||
|
||||
/// Type for converting the balance of an [Self::AssetKind] to the balance of the native
|
||||
/// asset, solely for the purpose of asserting the result against the maximum allowed spend
|
||||
/// amount of the [`Self::SpendOrigin`].
|
||||
type BalanceConverter: ConversionFromAssetBalance<
|
||||
<Self::Paymaster as Pay>::Balance,
|
||||
Self::AssetKind,
|
||||
BalanceOf<Self, I>,
|
||||
>;
|
||||
|
||||
/// The period during which an approved treasury spend has to be claimed.
|
||||
#[pallet::constant]
|
||||
type PayoutPeriod: Get<BlockNumberFor<Self>>;
|
||||
|
||||
/// Helper type for benchmarks.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper: ArgumentsFactory<Self::AssetKind, Self::Beneficiary>;
|
||||
}
|
||||
|
||||
/// Number of proposals that have been made.
|
||||
@@ -233,6 +317,27 @@ pub mod pallet {
|
||||
pub type Approvals<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, BoundedVec<ProposalIndex, T::MaxApprovals>, ValueQuery>;
|
||||
|
||||
/// The count of spends that have been made.
|
||||
#[pallet::storage]
|
||||
pub(crate) type SpendCount<T, I = ()> = StorageValue<_, SpendIndex, ValueQuery>;
|
||||
|
||||
/// Spends that have been approved and being processed.
|
||||
// Hasher: Twox safe since `SpendIndex` is an internal count based index.
|
||||
#[pallet::storage]
|
||||
pub type Spends<T: Config<I>, I: 'static = ()> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
SpendIndex,
|
||||
SpendStatus<
|
||||
T::AssetKind,
|
||||
AssetBalanceOf<T, I>,
|
||||
T::Beneficiary,
|
||||
BlockNumberFor<T>,
|
||||
<T::Paymaster as Pay>::Id,
|
||||
>,
|
||||
OptionQuery,
|
||||
>;
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[derive(frame_support::DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
|
||||
@@ -277,6 +382,24 @@ pub mod pallet {
|
||||
},
|
||||
/// The inactive funds of the pallet have been updated.
|
||||
UpdatedInactive { reactivated: BalanceOf<T, I>, deactivated: BalanceOf<T, I> },
|
||||
/// A new asset spend proposal has been approved.
|
||||
AssetSpendApproved {
|
||||
index: SpendIndex,
|
||||
asset_kind: T::AssetKind,
|
||||
amount: AssetBalanceOf<T, I>,
|
||||
beneficiary: T::Beneficiary,
|
||||
valid_from: BlockNumberFor<T>,
|
||||
expire_at: BlockNumberFor<T>,
|
||||
},
|
||||
/// An approved spend was voided.
|
||||
AssetSpendVoided { index: SpendIndex },
|
||||
/// A payment happened.
|
||||
Paid { index: SpendIndex, payment_id: <T::Paymaster as Pay>::Id },
|
||||
/// A payment failed and can be retried.
|
||||
PaymentFailed { index: SpendIndex, payment_id: <T::Paymaster as Pay>::Id },
|
||||
/// A spend was processed and removed from the storage. It might have been successfully
|
||||
/// paid or it may have expired.
|
||||
SpendProcessed { index: SpendIndex },
|
||||
}
|
||||
|
||||
/// Error for the treasury pallet.
|
||||
@@ -284,7 +407,7 @@ pub mod pallet {
|
||||
pub enum Error<T, I = ()> {
|
||||
/// Proposer's balance is too low.
|
||||
InsufficientProposersBalance,
|
||||
/// No proposal or bounty at that index.
|
||||
/// No proposal, bounty or spend at that index.
|
||||
InvalidIndex,
|
||||
/// Too many approvals in the queue.
|
||||
TooManyApprovals,
|
||||
@@ -293,6 +416,20 @@ pub mod pallet {
|
||||
InsufficientPermission,
|
||||
/// Proposal has not been approved.
|
||||
ProposalNotApproved,
|
||||
/// The balance of the asset kind is not convertible to the balance of the native asset.
|
||||
FailedToConvertBalance,
|
||||
/// The spend has expired and cannot be claimed.
|
||||
SpendExpired,
|
||||
/// The spend is not yet eligible for payout.
|
||||
EarlyPayout,
|
||||
/// The payment has already been attempted.
|
||||
AlreadyAttempted,
|
||||
/// There was some issue with the mechanism of payment.
|
||||
PayoutError,
|
||||
/// The payout was not yet attempted/claimed.
|
||||
NotAttempted,
|
||||
/// The payment has neither failed nor succeeded yet.
|
||||
Inconclusive,
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
@@ -328,12 +465,22 @@ pub mod pallet {
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
/// Put forward a suggestion for spending. A deposit proportional to the value
|
||||
/// is reserved and slashed if the proposal is rejected. It is returned once the
|
||||
/// proposal is awarded.
|
||||
/// Put forward a suggestion for spending.
|
||||
///
|
||||
/// ## Complexity
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// Must be signed.
|
||||
///
|
||||
/// ## Details
|
||||
/// A deposit proportional to the value is reserved and slashed if the proposal is rejected.
|
||||
/// It is returned once the proposal is awarded.
|
||||
///
|
||||
/// ### Complexity
|
||||
/// - O(1)
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Emits [`Event::Proposed`] if successful.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(T::WeightInfo::propose_spend())]
|
||||
#[allow(deprecated)]
|
||||
@@ -360,12 +507,21 @@ pub mod pallet {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reject a proposed spend. The original deposit will be slashed.
|
||||
/// Reject a proposed spend.
|
||||
///
|
||||
/// May only be called from `T::RejectOrigin`.
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// ## Complexity
|
||||
/// Must be [`Config::RejectOrigin`].
|
||||
///
|
||||
/// ## Details
|
||||
/// The original deposit will be slashed.
|
||||
///
|
||||
/// ### Complexity
|
||||
/// - O(1)
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Emits [`Event::Rejected`] if successful.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight((T::WeightInfo::reject_proposal(), DispatchClass::Operational))]
|
||||
#[allow(deprecated)]
|
||||
@@ -391,13 +547,23 @@ pub mod pallet {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary
|
||||
/// and the original deposit will be returned.
|
||||
/// Approve a proposal.
|
||||
///
|
||||
/// May only be called from `T::ApproveOrigin`.
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// ## Complexity
|
||||
/// Must be [`Config::ApproveOrigin`].
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// At a later time, the proposal will be allocated to the beneficiary and the original
|
||||
/// deposit will be returned.
|
||||
///
|
||||
/// ### Complexity
|
||||
/// - O(1).
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// No events are emitted from this dispatch.
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight((T::WeightInfo::approve_proposal(T::MaxApprovals::get()), DispatchClass::Operational))]
|
||||
#[allow(deprecated)]
|
||||
@@ -418,15 +584,24 @@ pub mod pallet {
|
||||
|
||||
/// Propose and approve a spend of treasury funds.
|
||||
///
|
||||
/// - `origin`: Must be `SpendOrigin` with the `Success` value being at least `amount`.
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// Must be [`Config::SpendOrigin`] with the `Success` value being at least `amount`.
|
||||
///
|
||||
/// ### Details
|
||||
/// NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the
|
||||
/// beneficiary.
|
||||
///
|
||||
/// ### Parameters
|
||||
/// - `amount`: The amount to be transferred from the treasury to the `beneficiary`.
|
||||
/// - `beneficiary`: The destination account for the transfer.
|
||||
///
|
||||
/// NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the
|
||||
/// beneficiary.
|
||||
/// ## Events
|
||||
///
|
||||
/// Emits [`Event::SpendApproved`] if successful.
|
||||
#[pallet::call_index(3)]
|
||||
#[pallet::weight(T::WeightInfo::spend())]
|
||||
pub fn spend(
|
||||
#[pallet::weight(T::WeightInfo::spend_local())]
|
||||
pub fn spend_local(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] amount: BalanceOf<T, I>,
|
||||
beneficiary: AccountIdLookupOf<T>,
|
||||
@@ -472,18 +647,26 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
/// Force a previously approved proposal to be removed from the approval queue.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// Must be [`Config::RejectOrigin`].
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// The original deposit will no longer be returned.
|
||||
///
|
||||
/// May only be called from `T::RejectOrigin`.
|
||||
/// ### Parameters
|
||||
/// - `proposal_id`: The index of a proposal
|
||||
///
|
||||
/// ## Complexity
|
||||
/// ### Complexity
|
||||
/// - O(A) where `A` is the number of approvals
|
||||
///
|
||||
/// Errors:
|
||||
/// - `ProposalNotApproved`: The `proposal_id` supplied was not found in the approval queue,
|
||||
/// i.e., the proposal has not been approved. This could also mean the proposal does not
|
||||
/// exist altogether, thus there is no way it would have been approved in the first place.
|
||||
/// ### Errors
|
||||
/// - [`Error::ProposalNotApproved`]: The `proposal_id` supplied was not found in the
|
||||
/// approval queue, i.e., the proposal has not been approved. This could also mean the
|
||||
/// proposal does not exist altogether, thus there is no way it would have been approved
|
||||
/// in the first place.
|
||||
#[pallet::call_index(4)]
|
||||
#[pallet::weight((T::WeightInfo::remove_approval(), DispatchClass::Operational))]
|
||||
pub fn remove_approval(
|
||||
@@ -503,6 +686,229 @@ pub mod pallet {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Propose and approve a spend of treasury funds.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// Must be [`Config::SpendOrigin`] with the `Success` value being at least
|
||||
/// `amount` of `asset_kind` in the native asset. The amount of `asset_kind` is converted
|
||||
/// for assertion using the [`Config::BalanceConverter`].
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// Create an approved spend for transferring a specific `amount` of `asset_kind` to a
|
||||
/// designated beneficiary. The spend must be claimed using the `payout` dispatchable within
|
||||
/// the [`Config::PayoutPeriod`].
|
||||
///
|
||||
/// ### Parameters
|
||||
/// - `asset_kind`: An indicator of the specific asset class to be spent.
|
||||
/// - `amount`: The amount to be transferred from the treasury to the `beneficiary`.
|
||||
/// - `beneficiary`: The beneficiary of the spend.
|
||||
/// - `valid_from`: The block number from which the spend can be claimed. It can refer to
|
||||
/// the past if the resulting spend has not yet expired according to the
|
||||
/// [`Config::PayoutPeriod`]. If `None`, the spend can be claimed immediately after
|
||||
/// approval.
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Emits [`Event::AssetSpendApproved`] if successful.
|
||||
#[pallet::call_index(5)]
|
||||
#[pallet::weight(T::WeightInfo::spend())]
|
||||
pub fn spend(
|
||||
origin: OriginFor<T>,
|
||||
asset_kind: Box<T::AssetKind>,
|
||||
#[pallet::compact] amount: AssetBalanceOf<T, I>,
|
||||
beneficiary: Box<BeneficiaryLookupOf<T, I>>,
|
||||
valid_from: Option<BlockNumberFor<T>>,
|
||||
) -> DispatchResult {
|
||||
let max_amount = T::SpendOrigin::ensure_origin(origin)?;
|
||||
let beneficiary = T::BeneficiaryLookup::lookup(*beneficiary)?;
|
||||
|
||||
let now = frame_system::Pallet::<T>::block_number();
|
||||
let valid_from = valid_from.unwrap_or(now);
|
||||
let expire_at = valid_from.saturating_add(T::PayoutPeriod::get());
|
||||
ensure!(expire_at > now, Error::<T, I>::SpendExpired);
|
||||
|
||||
let native_amount =
|
||||
T::BalanceConverter::from_asset_balance(amount, *asset_kind.clone())
|
||||
.map_err(|_| Error::<T, I>::FailedToConvertBalance)?;
|
||||
|
||||
ensure!(native_amount <= max_amount, Error::<T, I>::InsufficientPermission);
|
||||
|
||||
with_context::<SpendContext<BalanceOf<T, I>>, _>(|v| {
|
||||
let context = v.or_default();
|
||||
// We group based on `max_amount`, to distinguish between different kind of
|
||||
// origins. (assumes that all origins have different `max_amount`)
|
||||
//
|
||||
// Worst case is that we reject some "valid" request.
|
||||
let spend = context.spend_in_context.entry(max_amount).or_default();
|
||||
|
||||
// Ensure that we don't overflow nor use more than `max_amount`
|
||||
if spend.checked_add(&native_amount).map(|s| s > max_amount).unwrap_or(true) {
|
||||
Err(Error::<T, I>::InsufficientPermission)
|
||||
} else {
|
||||
*spend = spend.saturating_add(native_amount);
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.unwrap_or(Ok(()))?;
|
||||
|
||||
let index = SpendCount::<T, I>::get();
|
||||
Spends::<T, I>::insert(
|
||||
index,
|
||||
SpendStatus {
|
||||
asset_kind: *asset_kind.clone(),
|
||||
amount,
|
||||
beneficiary: beneficiary.clone(),
|
||||
valid_from,
|
||||
expire_at,
|
||||
status: PaymentState::Pending,
|
||||
},
|
||||
);
|
||||
SpendCount::<T, I>::put(index + 1);
|
||||
|
||||
Self::deposit_event(Event::AssetSpendApproved {
|
||||
index,
|
||||
asset_kind: *asset_kind,
|
||||
amount,
|
||||
beneficiary,
|
||||
valid_from,
|
||||
expire_at,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Claim a spend.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// Must be signed.
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// Spends must be claimed within some temporal bounds. A spend may be claimed within one
|
||||
/// [`Config::PayoutPeriod`] from the `valid_from` block.
|
||||
/// In case of a payout failure, the spend status must be updated with the `check_status`
|
||||
/// dispatchable before retrying with the current function.
|
||||
///
|
||||
/// ### Parameters
|
||||
/// - `index`: The spend index.
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Emits [`Event::Paid`] if successful.
|
||||
#[pallet::call_index(6)]
|
||||
#[pallet::weight(T::WeightInfo::payout())]
|
||||
pub fn payout(origin: OriginFor<T>, index: SpendIndex) -> DispatchResult {
|
||||
ensure_signed(origin)?;
|
||||
let mut spend = Spends::<T, I>::get(index).ok_or(Error::<T, I>::InvalidIndex)?;
|
||||
let now = frame_system::Pallet::<T>::block_number();
|
||||
ensure!(now >= spend.valid_from, Error::<T, I>::EarlyPayout);
|
||||
ensure!(spend.expire_at > now, Error::<T, I>::SpendExpired);
|
||||
ensure!(
|
||||
matches!(spend.status, PaymentState::Pending | PaymentState::Failed),
|
||||
Error::<T, I>::AlreadyAttempted
|
||||
);
|
||||
|
||||
let id = T::Paymaster::pay(&spend.beneficiary, spend.asset_kind.clone(), spend.amount)
|
||||
.map_err(|_| Error::<T, I>::PayoutError)?;
|
||||
|
||||
spend.status = PaymentState::Attempted { id };
|
||||
Spends::<T, I>::insert(index, spend);
|
||||
|
||||
Self::deposit_event(Event::<T, I>::Paid { index, payment_id: id });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check the status of the spend and remove it from the storage if processed.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// Must be signed.
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// The status check is a prerequisite for retrying a failed payout.
|
||||
/// If a spend has either succeeded or expired, it is removed from the storage by this
|
||||
/// function. In such instances, transaction fees are refunded.
|
||||
///
|
||||
/// ### Parameters
|
||||
/// - `index`: The spend index.
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Emits [`Event::PaymentFailed`] if the spend payout has failed.
|
||||
/// Emits [`Event::SpendProcessed`] if the spend payout has succeed.
|
||||
#[pallet::call_index(7)]
|
||||
#[pallet::weight(T::WeightInfo::check_status())]
|
||||
pub fn check_status(origin: OriginFor<T>, index: SpendIndex) -> DispatchResultWithPostInfo {
|
||||
use PaymentState as State;
|
||||
use PaymentStatus as Status;
|
||||
|
||||
ensure_signed(origin)?;
|
||||
let mut spend = Spends::<T, I>::get(index).ok_or(Error::<T, I>::InvalidIndex)?;
|
||||
let now = frame_system::Pallet::<T>::block_number();
|
||||
|
||||
if now > spend.expire_at && !matches!(spend.status, State::Attempted { .. }) {
|
||||
// spend has expired and no further status update is expected.
|
||||
Spends::<T, I>::remove(index);
|
||||
Self::deposit_event(Event::<T, I>::SpendProcessed { index });
|
||||
return Ok(Pays::No.into())
|
||||
}
|
||||
|
||||
let payment_id = match spend.status {
|
||||
State::Attempted { id } => id,
|
||||
_ => return Err(Error::<T, I>::NotAttempted.into()),
|
||||
};
|
||||
|
||||
match T::Paymaster::check_payment(payment_id) {
|
||||
Status::Failure => {
|
||||
spend.status = PaymentState::Failed;
|
||||
Spends::<T, I>::insert(index, spend);
|
||||
Self::deposit_event(Event::<T, I>::PaymentFailed { index, payment_id });
|
||||
},
|
||||
Status::Success | Status::Unknown => {
|
||||
Spends::<T, I>::remove(index);
|
||||
Self::deposit_event(Event::<T, I>::SpendProcessed { index });
|
||||
return Ok(Pays::No.into())
|
||||
},
|
||||
Status::InProgress => return Err(Error::<T, I>::Inconclusive.into()),
|
||||
}
|
||||
return Ok(Pays::Yes.into())
|
||||
}
|
||||
|
||||
/// Void previously approved spend.
|
||||
///
|
||||
/// ## Dispatch Origin
|
||||
///
|
||||
/// Must be [`Config::RejectOrigin`].
|
||||
///
|
||||
/// ## Details
|
||||
///
|
||||
/// A spend void is only possible if the payout has not been attempted yet.
|
||||
///
|
||||
/// ### Parameters
|
||||
/// - `index`: The spend index.
|
||||
///
|
||||
/// ## Events
|
||||
///
|
||||
/// Emits [`Event::AssetSpendVoided`] if successful.
|
||||
#[pallet::call_index(8)]
|
||||
#[pallet::weight(T::WeightInfo::void_spend())]
|
||||
pub fn void_spend(origin: OriginFor<T>, index: SpendIndex) -> DispatchResult {
|
||||
T::RejectOrigin::ensure_origin(origin)?;
|
||||
let spend = Spends::<T, I>::get(index).ok_or(Error::<T, I>::InvalidIndex)?;
|
||||
ensure!(
|
||||
matches!(spend.status, PaymentState::Pending | PaymentState::Failed),
|
||||
Error::<T, I>::AlreadyAttempted
|
||||
);
|
||||
|
||||
Spends::<T, I>::remove(index);
|
||||
Self::deposit_event(Event::<T, I>::AssetSpendVoided { index });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use core::{cell::RefCell, marker::PhantomData};
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
traits::{BadOrigin, BlakeTwo256, Dispatchable, IdentityLookup},
|
||||
@@ -26,8 +27,13 @@ use sp_runtime::{
|
||||
};
|
||||
|
||||
use frame_support::{
|
||||
assert_err_ignore_postinfo, assert_noop, assert_ok, parameter_types,
|
||||
traits::{ConstU32, ConstU64, OnInitialize},
|
||||
assert_err_ignore_postinfo, assert_noop, assert_ok,
|
||||
pallet_prelude::Pays,
|
||||
parameter_types,
|
||||
traits::{
|
||||
tokens::{ConversionFromAssetBalance, PaymentStatus},
|
||||
ConstU32, ConstU64, OnInitialize,
|
||||
},
|
||||
PalletId,
|
||||
};
|
||||
|
||||
@@ -96,10 +102,64 @@ impl pallet_utility::Config for Test {
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
pub static PAID: RefCell<BTreeMap<(u128, u32), u64>> = RefCell::new(BTreeMap::new());
|
||||
pub static STATUS: RefCell<BTreeMap<u64, PaymentStatus>> = RefCell::new(BTreeMap::new());
|
||||
pub static LAST_ID: RefCell<u64> = RefCell::new(0u64);
|
||||
}
|
||||
|
||||
/// paid balance for a given account and asset ids
|
||||
fn paid(who: u128, asset_id: u32) -> u64 {
|
||||
PAID.with(|p| p.borrow().get(&(who, asset_id)).cloned().unwrap_or(0))
|
||||
}
|
||||
|
||||
/// reduce paid balance for a given account and asset ids
|
||||
fn unpay(who: u128, asset_id: u32, amount: u64) {
|
||||
PAID.with(|p| p.borrow_mut().entry((who, asset_id)).or_default().saturating_reduce(amount))
|
||||
}
|
||||
|
||||
/// set status for a given payment id
|
||||
fn set_status(id: u64, s: PaymentStatus) {
|
||||
STATUS.with(|m| m.borrow_mut().insert(id, s));
|
||||
}
|
||||
|
||||
pub struct TestPay;
|
||||
impl Pay for TestPay {
|
||||
type Beneficiary = u128;
|
||||
type Balance = u64;
|
||||
type Id = u64;
|
||||
type AssetKind = u32;
|
||||
type Error = ();
|
||||
|
||||
fn pay(
|
||||
who: &Self::Beneficiary,
|
||||
asset_kind: Self::AssetKind,
|
||||
amount: Self::Balance,
|
||||
) -> Result<Self::Id, Self::Error> {
|
||||
PAID.with(|paid| *paid.borrow_mut().entry((*who, asset_kind)).or_default() += amount);
|
||||
Ok(LAST_ID.with(|lid| {
|
||||
let x = *lid.borrow();
|
||||
lid.replace(x + 1);
|
||||
x
|
||||
}))
|
||||
}
|
||||
fn check_payment(id: Self::Id) -> PaymentStatus {
|
||||
STATUS.with(|s| s.borrow().get(&id).cloned().unwrap_or(PaymentStatus::Unknown))
|
||||
}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_successful(_: &Self::Beneficiary, _: Self::AssetKind, _: Self::Balance) {}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_concluded(id: Self::Id) {
|
||||
set_status(id, PaymentStatus::Failure)
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ProposalBond: Permill = Permill::from_percent(5);
|
||||
pub const Burn: Permill = Permill::from_percent(50);
|
||||
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
|
||||
pub TreasuryAccount: u128 = Treasury::account_id();
|
||||
pub const SpendPayoutPeriod: u64 = 5;
|
||||
}
|
||||
pub struct TestSpendOrigin;
|
||||
impl frame_support::traits::EnsureOrigin<RuntimeOrigin> for TestSpendOrigin {
|
||||
@@ -120,6 +180,16 @@ impl frame_support::traits::EnsureOrigin<RuntimeOrigin> for TestSpendOrigin {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MulBy<N>(PhantomData<N>);
|
||||
impl<N: Get<u64>> ConversionFromAssetBalance<u64, u32, u64> for MulBy<N> {
|
||||
type Error = ();
|
||||
fn from_asset_balance(balance: u64, _asset_id: u32) -> Result<u64, Self::Error> {
|
||||
return balance.checked_mul(N::get()).ok_or(())
|
||||
}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn ensure_successful(_: u32) {}
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
type PalletId = TreasuryPalletId;
|
||||
type Currency = pallet_balances::Pallet<Test>;
|
||||
@@ -137,6 +207,14 @@ impl Config for Test {
|
||||
type SpendFunds = ();
|
||||
type MaxApprovals = ConstU32<100>;
|
||||
type SpendOrigin = TestSpendOrigin;
|
||||
type AssetKind = u32;
|
||||
type Beneficiary = u128;
|
||||
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
|
||||
type Paymaster = TestPay;
|
||||
type BalanceConverter = MulBy<ConstU64<2>>;
|
||||
type PayoutPeriod = SpendPayoutPeriod;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
@@ -151,6 +229,14 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
t.into()
|
||||
}
|
||||
|
||||
fn get_payment_id(i: SpendIndex) -> Option<u64> {
|
||||
let spend = Spends::<Test, _>::get(i).expect("no spend");
|
||||
match spend.status {
|
||||
PaymentState::Attempted { id } => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_config_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
@@ -160,46 +246,49 @@ fn genesis_config_works() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_origin_permissioning_works() {
|
||||
fn spend_local_origin_permissioning_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(Treasury::spend(RuntimeOrigin::signed(1), 1, 1), BadOrigin);
|
||||
assert_noop!(Treasury::spend_local(RuntimeOrigin::signed(1), 1, 1), BadOrigin);
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(10), 6, 1),
|
||||
Treasury::spend_local(RuntimeOrigin::signed(10), 6, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(11), 11, 1),
|
||||
Treasury::spend_local(RuntimeOrigin::signed(11), 11, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(12), 21, 1),
|
||||
Treasury::spend_local(RuntimeOrigin::signed(12), 21, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(13), 51, 1),
|
||||
Treasury::spend_local(RuntimeOrigin::signed(13), 51, 1),
|
||||
Error::<Test>::InsufficientPermission
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[test]
|
||||
fn spend_origin_works() {
|
||||
fn spend_local_origin_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Check that accumulate works when we have Some value in Dummy already.
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(11), 10, 6));
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(12), 20, 6));
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(13), 50, 6));
|
||||
|
||||
// approve spend of some amount to beneficiary `6`.
|
||||
assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6));
|
||||
assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(11), 10, 6));
|
||||
assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(12), 20, 6));
|
||||
assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(13), 50, 6));
|
||||
// free balance of `6` is zero, spend period has not passed.
|
||||
<Treasury as OnInitialize<u64>>::on_initialize(1);
|
||||
assert_eq!(Balances::free_balance(6), 0);
|
||||
|
||||
// free balance of `6` is `100`, spend period has passed.
|
||||
<Treasury as OnInitialize<u64>>::on_initialize(2);
|
||||
assert_eq!(Balances::free_balance(6), 100);
|
||||
// `100` spent, `1` burned.
|
||||
assert_eq!(Treasury::pot(), 0);
|
||||
});
|
||||
}
|
||||
@@ -579,13 +668,13 @@ fn remove_already_removed_approval_fails() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spending_in_batch_respects_max_total() {
|
||||
fn spending_local_in_batch_respects_max_total() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Respect the `max_total` for the given origin.
|
||||
assert_ok!(RuntimeCall::from(UtilityCall::batch_all {
|
||||
calls: vec![
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }),
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 101 })
|
||||
RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 100 }),
|
||||
RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 101 })
|
||||
]
|
||||
})
|
||||
.dispatch(RuntimeOrigin::signed(10)));
|
||||
@@ -593,8 +682,8 @@ fn spending_in_batch_respects_max_total() {
|
||||
assert_err_ignore_postinfo!(
|
||||
RuntimeCall::from(UtilityCall::batch_all {
|
||||
calls: vec![
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }),
|
||||
RuntimeCall::from(TreasuryCall::spend { amount: 4, beneficiary: 101 })
|
||||
RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 100 }),
|
||||
RuntimeCall::from(TreasuryCall::spend_local { amount: 4, beneficiary: 101 })
|
||||
]
|
||||
})
|
||||
.dispatch(RuntimeOrigin::signed(10)),
|
||||
@@ -602,3 +691,296 @@ fn spending_in_batch_respects_max_total() {
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spending_in_batch_respects_max_total() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Respect the `max_total` for the given origin.
|
||||
assert_ok!(RuntimeCall::from(UtilityCall::batch_all {
|
||||
calls: vec![
|
||||
RuntimeCall::from(TreasuryCall::spend {
|
||||
asset_kind: Box::new(1),
|
||||
amount: 1,
|
||||
beneficiary: Box::new(100),
|
||||
valid_from: None,
|
||||
}),
|
||||
RuntimeCall::from(TreasuryCall::spend {
|
||||
asset_kind: Box::new(1),
|
||||
amount: 1,
|
||||
beneficiary: Box::new(101),
|
||||
valid_from: None,
|
||||
})
|
||||
]
|
||||
})
|
||||
.dispatch(RuntimeOrigin::signed(10)));
|
||||
|
||||
assert_err_ignore_postinfo!(
|
||||
RuntimeCall::from(UtilityCall::batch_all {
|
||||
calls: vec![
|
||||
RuntimeCall::from(TreasuryCall::spend {
|
||||
asset_kind: Box::new(1),
|
||||
amount: 2,
|
||||
beneficiary: Box::new(100),
|
||||
valid_from: None,
|
||||
}),
|
||||
RuntimeCall::from(TreasuryCall::spend {
|
||||
asset_kind: Box::new(1),
|
||||
amount: 2,
|
||||
beneficiary: Box::new(101),
|
||||
valid_from: None,
|
||||
})
|
||||
]
|
||||
})
|
||||
.dispatch(RuntimeOrigin::signed(10)),
|
||||
Error::<Test, _>::InsufficientPermission
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_origin_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 1, Box::new(6), None));
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 3, Box::new(6), None),
|
||||
Error::<Test, _>::InsufficientPermission
|
||||
);
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(11), Box::new(1), 5, Box::new(6), None));
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(11), Box::new(1), 6, Box::new(6), None),
|
||||
Error::<Test, _>::InsufficientPermission
|
||||
);
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(12), Box::new(1), 10, Box::new(6), None));
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(12), Box::new(1), 11, Box::new(6), None),
|
||||
Error::<Test, _>::InsufficientPermission
|
||||
);
|
||||
|
||||
assert_eq!(SpendCount::<Test, _>::get(), 4);
|
||||
assert_eq!(Spends::<Test, _>::iter().count(), 4);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
|
||||
assert_eq!(SpendCount::<Test, _>::get(), 1);
|
||||
assert_eq!(
|
||||
Spends::<Test, _>::get(0).unwrap(),
|
||||
SpendStatus {
|
||||
asset_kind: 1,
|
||||
amount: 2,
|
||||
beneficiary: 6,
|
||||
valid_from: 1,
|
||||
expire_at: 6,
|
||||
status: PaymentState::Pending,
|
||||
}
|
||||
);
|
||||
System::assert_last_event(
|
||||
Event::<Test, _>::AssetSpendApproved {
|
||||
index: 0,
|
||||
asset_kind: 1,
|
||||
amount: 2,
|
||||
beneficiary: 6,
|
||||
valid_from: 1,
|
||||
expire_at: 6,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_expires() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(<Test as Config>::PayoutPeriod::get(), 5);
|
||||
|
||||
// spend `0` expires in 5 blocks after the creating.
|
||||
System::set_block_number(1);
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
System::set_block_number(6);
|
||||
assert_noop!(Treasury::payout(RuntimeOrigin::signed(1), 0), Error::<Test, _>::SpendExpired);
|
||||
|
||||
// spend cannot be approved since its already expired.
|
||||
assert_noop!(
|
||||
Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), Some(0)),
|
||||
Error::<Test, _>::SpendExpired
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[test]
|
||||
fn spend_payout_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
// approve a `2` coins spend of asset `1` to beneficiary `6`, the spend valid from now.
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
// payout the spend.
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0));
|
||||
// beneficiary received `2` coins of asset `1`.
|
||||
assert_eq!(paid(6, 1), 2);
|
||||
assert_eq!(SpendCount::<Test, _>::get(), 1);
|
||||
let payment_id = get_payment_id(0).expect("no payment attempt");
|
||||
System::assert_last_event(Event::<Test, _>::Paid { index: 0, payment_id }.into());
|
||||
set_status(payment_id, PaymentStatus::Success);
|
||||
// the payment succeed.
|
||||
assert_ok!(Treasury::check_status(RuntimeOrigin::signed(1), 0));
|
||||
System::assert_last_event(Event::<Test, _>::SpendProcessed { index: 0 }.into());
|
||||
// cannot payout the same spend twice.
|
||||
assert_noop!(Treasury::payout(RuntimeOrigin::signed(1), 0), Error::<Test, _>::InvalidIndex);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payout_retry_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0));
|
||||
assert_eq!(paid(6, 1), 2);
|
||||
let payment_id = get_payment_id(0).expect("no payment attempt");
|
||||
// spend payment is failed
|
||||
set_status(payment_id, PaymentStatus::Failure);
|
||||
unpay(6, 1, 2);
|
||||
// cannot payout a spend in the attempted state
|
||||
assert_noop!(
|
||||
Treasury::payout(RuntimeOrigin::signed(1), 0),
|
||||
Error::<Test, _>::AlreadyAttempted
|
||||
);
|
||||
// check status and update it to retry the payout again
|
||||
assert_ok!(Treasury::check_status(RuntimeOrigin::signed(1), 0));
|
||||
System::assert_last_event(Event::<Test, _>::PaymentFailed { index: 0, payment_id }.into());
|
||||
// the payout can be retried now
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0));
|
||||
assert_eq!(paid(6, 1), 2);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spend_valid_from_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(<Test as Config>::PayoutPeriod::get(), 5);
|
||||
System::set_block_number(1);
|
||||
|
||||
// spend valid from block `2`.
|
||||
assert_ok!(Treasury::spend(
|
||||
RuntimeOrigin::signed(10),
|
||||
Box::new(1),
|
||||
2,
|
||||
Box::new(6),
|
||||
Some(2)
|
||||
));
|
||||
assert_noop!(Treasury::payout(RuntimeOrigin::signed(1), 0), Error::<Test, _>::EarlyPayout);
|
||||
System::set_block_number(2);
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0));
|
||||
|
||||
System::set_block_number(5);
|
||||
// spend approved even if `valid_from` in the past since the payout period has not passed.
|
||||
assert_ok!(Treasury::spend(
|
||||
RuntimeOrigin::signed(10),
|
||||
Box::new(1),
|
||||
2,
|
||||
Box::new(6),
|
||||
Some(4)
|
||||
));
|
||||
// spend paid.
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 1));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn void_spend_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
// spend cannot be voided if already attempted.
|
||||
assert_ok!(Treasury::spend(
|
||||
RuntimeOrigin::signed(10),
|
||||
Box::new(1),
|
||||
2,
|
||||
Box::new(6),
|
||||
Some(1)
|
||||
));
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 0));
|
||||
assert_noop!(
|
||||
Treasury::void_spend(RuntimeOrigin::root(), 0),
|
||||
Error::<Test, _>::AlreadyAttempted
|
||||
);
|
||||
|
||||
// void spend.
|
||||
assert_ok!(Treasury::spend(
|
||||
RuntimeOrigin::signed(10),
|
||||
Box::new(1),
|
||||
2,
|
||||
Box::new(6),
|
||||
Some(10)
|
||||
));
|
||||
assert_ok!(Treasury::void_spend(RuntimeOrigin::root(), 1));
|
||||
assert_eq!(Spends::<Test, _>::get(1), None);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_status_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(<Test as Config>::PayoutPeriod::get(), 5);
|
||||
System::set_block_number(1);
|
||||
|
||||
// spend `0` expired and can be removed.
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
System::set_block_number(7);
|
||||
let info = Treasury::check_status(RuntimeOrigin::signed(1), 0).unwrap();
|
||||
assert_eq!(info.pays_fee, Pays::No);
|
||||
System::assert_last_event(Event::<Test, _>::SpendProcessed { index: 0 }.into());
|
||||
|
||||
// spend `1` payment failed and expired hence can be removed.
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
assert_noop!(
|
||||
Treasury::check_status(RuntimeOrigin::signed(1), 1),
|
||||
Error::<Test, _>::NotAttempted
|
||||
);
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 1));
|
||||
let payment_id = get_payment_id(1).expect("no payment attempt");
|
||||
set_status(payment_id, PaymentStatus::Failure);
|
||||
// spend expired.
|
||||
System::set_block_number(13);
|
||||
let info = Treasury::check_status(RuntimeOrigin::signed(1), 1).unwrap();
|
||||
assert_eq!(info.pays_fee, Pays::Yes);
|
||||
System::assert_last_event(Event::<Test, _>::PaymentFailed { index: 1, payment_id }.into());
|
||||
let info = Treasury::check_status(RuntimeOrigin::signed(1), 1).unwrap();
|
||||
assert_eq!(info.pays_fee, Pays::No);
|
||||
System::assert_last_event(Event::<Test, _>::SpendProcessed { index: 1 }.into());
|
||||
|
||||
// spend `2` payment succeed.
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 2));
|
||||
let payment_id = get_payment_id(2).expect("no payment attempt");
|
||||
set_status(payment_id, PaymentStatus::Success);
|
||||
let info = Treasury::check_status(RuntimeOrigin::signed(1), 2).unwrap();
|
||||
assert_eq!(info.pays_fee, Pays::No);
|
||||
System::assert_last_event(Event::<Test, _>::SpendProcessed { index: 2 }.into());
|
||||
|
||||
// spend `3` payment in process.
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 3));
|
||||
let payment_id = get_payment_id(3).expect("no payment attempt");
|
||||
set_status(payment_id, PaymentStatus::InProgress);
|
||||
assert_noop!(
|
||||
Treasury::check_status(RuntimeOrigin::signed(1), 3),
|
||||
Error::<Test, _>::Inconclusive
|
||||
);
|
||||
|
||||
// spend `4` removed since the payment status is unknown.
|
||||
assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), Box::new(1), 2, Box::new(6), None));
|
||||
assert_ok!(Treasury::payout(RuntimeOrigin::signed(1), 4));
|
||||
let payment_id = get_payment_id(4).expect("no payment attempt");
|
||||
set_status(payment_id, PaymentStatus::Unknown);
|
||||
let info = Treasury::check_status(RuntimeOrigin::signed(1), 4).unwrap();
|
||||
assert_eq!(info.pays_fee, Pays::No);
|
||||
System::assert_last_event(Event::<Test, _>::SpendProcessed { index: 4 }.into());
|
||||
});
|
||||
}
|
||||
|
||||
Generated
+165
-58
@@ -18,28 +18,23 @@
|
||||
//! Autogenerated weights for pallet_treasury
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2023-07-07, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
|
||||
//! HOSTNAME: `cob`, CPU: `<UNKNOWN>`
|
||||
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/substrate
|
||||
// ./target/debug/substrate
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=pallet_treasury
|
||||
// --no-storage-info
|
||||
// --no-median-slopes
|
||||
// --no-min-squares
|
||||
// --steps=20
|
||||
// --repeat=2
|
||||
// --pallet=pallet-treasury
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./frame/treasury/src/weights.rs
|
||||
// --header=./HEADER-APACHE2
|
||||
// --output=./frame/treasury/src/._weights.rs
|
||||
// --template=./.maintain/frame-weight-template.hbs
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
@@ -52,12 +47,16 @@ use core::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for pallet_treasury.
|
||||
pub trait WeightInfo {
|
||||
fn spend() -> Weight;
|
||||
fn spend_local() -> Weight;
|
||||
fn propose_spend() -> Weight;
|
||||
fn reject_proposal() -> Weight;
|
||||
fn approve_proposal(p: u32, ) -> Weight;
|
||||
fn remove_approval() -> Weight;
|
||||
fn on_initialize_proposals(p: u32, ) -> Weight;
|
||||
fn spend() -> Weight;
|
||||
fn payout() -> Weight;
|
||||
fn check_status() -> Weight;
|
||||
fn void_spend() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for pallet_treasury using the Substrate node and recommended hardware.
|
||||
@@ -69,12 +68,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:0 w:1)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
fn spend() -> Weight {
|
||||
fn spend_local() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `76`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 15_057_000 picoseconds.
|
||||
Weight::from_parts(15_803_000, 1887)
|
||||
// Minimum execution time: 179_000_000 picoseconds.
|
||||
Weight::from_parts(190_000_000, 1887)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
}
|
||||
@@ -86,8 +85,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `177`
|
||||
// Estimated: `1489`
|
||||
// Minimum execution time: 28_923_000 picoseconds.
|
||||
Weight::from_parts(29_495_000, 1489)
|
||||
// Minimum execution time: 349_000_000 picoseconds.
|
||||
Weight::from_parts(398_000_000, 1489)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
@@ -99,8 +98,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `335`
|
||||
// Estimated: `3593`
|
||||
// Minimum execution time: 30_539_000 picoseconds.
|
||||
Weight::from_parts(30_986_000, 3593)
|
||||
// Minimum execution time: 367_000_000 picoseconds.
|
||||
Weight::from_parts(388_000_000, 3593)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
@@ -111,12 +110,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn approve_proposal(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `504 + p * (8 ±0)`
|
||||
// Measured: `483 + p * (9 ±0)`
|
||||
// Estimated: `3573`
|
||||
// Minimum execution time: 9_320_000 picoseconds.
|
||||
Weight::from_parts(12_606_599, 3573)
|
||||
// Standard Error: 1_302
|
||||
.saturating_add(Weight::from_parts(71_054, 0).saturating_mul(p.into()))
|
||||
// Minimum execution time: 111_000_000 picoseconds.
|
||||
Weight::from_parts(108_813_243, 3573)
|
||||
// Standard Error: 147_887
|
||||
.saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
@@ -126,8 +125,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `161`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 7_231_000 picoseconds.
|
||||
Weight::from_parts(7_459_000, 1887)
|
||||
// Minimum execution time: 71_000_000 picoseconds.
|
||||
Weight::from_parts(78_000_000, 1887)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
@@ -135,27 +134,81 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
/// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:100 w:100)
|
||||
/// Storage: Treasury Proposals (r:99 w:99)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
/// Storage: System Account (r:200 w:200)
|
||||
/// Storage: System Account (r:198 w:198)
|
||||
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
|
||||
/// Storage: Bounties BountyApprovals (r:1 w:1)
|
||||
/// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// The range of component `p` is `[0, 100]`.
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn on_initialize_proposals(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `421 + p * (251 ±0)`
|
||||
// Measured: `427 + p * (251 ±0)`
|
||||
// Estimated: `1887 + p * (5206 ±0)`
|
||||
// Minimum execution time: 44_769_000 picoseconds.
|
||||
Weight::from_parts(57_915_572, 1887)
|
||||
// Standard Error: 59_484
|
||||
.saturating_add(Weight::from_parts(42_343_732, 0).saturating_mul(p.into()))
|
||||
// Minimum execution time: 614_000_000 picoseconds.
|
||||
Weight::from_parts(498_501_558, 1887)
|
||||
// Standard Error: 1_070_260
|
||||
.saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(3_u64))
|
||||
.saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into())))
|
||||
.saturating_add(T::DbWeight::get().writes(3_u64))
|
||||
.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(36), added: 2511, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury SpendCount (r:1 w:1)
|
||||
/// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Spends (r:0 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
fn spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `140`
|
||||
// Estimated: `3501`
|
||||
// Minimum execution time: 214_000_000 picoseconds.
|
||||
Weight::from_parts(216_000_000, 3501)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
/// Storage: Assets Asset (r:1 w:1)
|
||||
/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
|
||||
/// Storage: Assets Account (r:2 w:2)
|
||||
/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
|
||||
/// Storage: System Account (r:1 w:1)
|
||||
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
|
||||
fn payout() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `705`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 760_000_000 picoseconds.
|
||||
Weight::from_parts(822_000_000, 6208)
|
||||
.saturating_add(T::DbWeight::get().reads(5_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(5_u64))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
fn check_status() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `194`
|
||||
// Estimated: `3534`
|
||||
// Minimum execution time: 153_000_000 picoseconds.
|
||||
Weight::from_parts(160_000_000, 3534)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
fn void_spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `194`
|
||||
// Estimated: `3534`
|
||||
// Minimum execution time: 147_000_000 picoseconds.
|
||||
Weight::from_parts(181_000_000, 3534)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests
|
||||
@@ -166,12 +219,12 @@ impl WeightInfo for () {
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:0 w:1)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
fn spend() -> Weight {
|
||||
fn spend_local() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `76`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 15_057_000 picoseconds.
|
||||
Weight::from_parts(15_803_000, 1887)
|
||||
// Minimum execution time: 179_000_000 picoseconds.
|
||||
Weight::from_parts(190_000_000, 1887)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
}
|
||||
@@ -183,8 +236,8 @@ impl WeightInfo for () {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `177`
|
||||
// Estimated: `1489`
|
||||
// Minimum execution time: 28_923_000 picoseconds.
|
||||
Weight::from_parts(29_495_000, 1489)
|
||||
// Minimum execution time: 349_000_000 picoseconds.
|
||||
Weight::from_parts(398_000_000, 1489)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
@@ -196,8 +249,8 @@ impl WeightInfo for () {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `335`
|
||||
// Estimated: `3593`
|
||||
// Minimum execution time: 30_539_000 picoseconds.
|
||||
Weight::from_parts(30_986_000, 3593)
|
||||
// Minimum execution time: 367_000_000 picoseconds.
|
||||
Weight::from_parts(388_000_000, 3593)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
@@ -208,12 +261,12 @@ impl WeightInfo for () {
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn approve_proposal(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `504 + p * (8 ±0)`
|
||||
// Measured: `483 + p * (9 ±0)`
|
||||
// Estimated: `3573`
|
||||
// Minimum execution time: 9_320_000 picoseconds.
|
||||
Weight::from_parts(12_606_599, 3573)
|
||||
// Standard Error: 1_302
|
||||
.saturating_add(Weight::from_parts(71_054, 0).saturating_mul(p.into()))
|
||||
// Minimum execution time: 111_000_000 picoseconds.
|
||||
Weight::from_parts(108_813_243, 3573)
|
||||
// Standard Error: 147_887
|
||||
.saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
@@ -223,8 +276,8 @@ impl WeightInfo for () {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `161`
|
||||
// Estimated: `1887`
|
||||
// Minimum execution time: 7_231_000 picoseconds.
|
||||
Weight::from_parts(7_459_000, 1887)
|
||||
// Minimum execution time: 71_000_000 picoseconds.
|
||||
Weight::from_parts(78_000_000, 1887)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
@@ -232,25 +285,79 @@ impl WeightInfo for () {
|
||||
/// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Approvals (r:1 w:1)
|
||||
/// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Proposals (r:100 w:100)
|
||||
/// Storage: Treasury Proposals (r:99 w:99)
|
||||
/// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen)
|
||||
/// Storage: System Account (r:200 w:200)
|
||||
/// Storage: System Account (r:198 w:198)
|
||||
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
|
||||
/// Storage: Bounties BountyApprovals (r:1 w:1)
|
||||
/// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen)
|
||||
/// The range of component `p` is `[0, 100]`.
|
||||
/// The range of component `p` is `[0, 99]`.
|
||||
fn on_initialize_proposals(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `421 + p * (251 ±0)`
|
||||
// Measured: `427 + p * (251 ±0)`
|
||||
// Estimated: `1887 + p * (5206 ±0)`
|
||||
// Minimum execution time: 44_769_000 picoseconds.
|
||||
Weight::from_parts(57_915_572, 1887)
|
||||
// Standard Error: 59_484
|
||||
.saturating_add(Weight::from_parts(42_343_732, 0).saturating_mul(p.into()))
|
||||
// Minimum execution time: 614_000_000 picoseconds.
|
||||
Weight::from_parts(498_501_558, 1887)
|
||||
// Standard Error: 1_070_260
|
||||
.saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(3_u64))
|
||||
.saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into())))
|
||||
.saturating_add(RocksDbWeight::get().writes(3_u64))
|
||||
.saturating_add(RocksDbWeight::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(36), added: 2511, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury SpendCount (r:1 w:1)
|
||||
/// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
/// Storage: Treasury Spends (r:0 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
fn spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `140`
|
||||
// Estimated: `3501`
|
||||
// Minimum execution time: 214_000_000 picoseconds.
|
||||
Weight::from_parts(216_000_000, 3501)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(2_u64))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
/// Storage: Assets Asset (r:1 w:1)
|
||||
/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
|
||||
/// Storage: Assets Account (r:2 w:2)
|
||||
/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
|
||||
/// Storage: System Account (r:1 w:1)
|
||||
/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
|
||||
fn payout() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `705`
|
||||
// Estimated: `6208`
|
||||
// Minimum execution time: 760_000_000 picoseconds.
|
||||
Weight::from_parts(822_000_000, 6208)
|
||||
.saturating_add(RocksDbWeight::get().reads(5_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(5_u64))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
fn check_status() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `194`
|
||||
// Estimated: `3534`
|
||||
// Minimum execution time: 153_000_000 picoseconds.
|
||||
Weight::from_parts(160_000_000, 3534)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: Treasury Spends (r:1 w:1)
|
||||
/// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen)
|
||||
fn void_spend() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `194`
|
||||
// Estimated: `3534`
|
||||
// Minimum execution time: 147_000_000 picoseconds.
|
||||
Weight::from_parts(181_000_000, 3534)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,6 +630,13 @@ impl sp_std::str::FromStr for AccountId32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an [`AccountId32`] from the input, which should contain at least 32 bytes.
|
||||
impl FromEntropy for AccountId32 {
|
||||
fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
|
||||
Ok(AccountId32::new(FromEntropy::from_entropy(input)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::dummy::*;
|
||||
|
||||
@@ -1171,6 +1178,13 @@ impl FromEntropy for bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create the unit type for any given input.
|
||||
impl FromEntropy for () {
|
||||
fn from_entropy(_: &mut impl codec::Input) -> Result<Self, codec::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_entropy {
|
||||
($type:ty , $( $others:tt )*) => {
|
||||
impl_from_entropy!($type);
|
||||
|
||||
Reference in New Issue
Block a user