Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn create_and_claim_treasury_spend() {
// create and approve a treasury spend.
assert_ok!(FellowshipTreasury::spend(
root,
Box::new(asset_kind),
Box::new(pallet_treasury::SpendAsset::Specific(asset_kind)),
SPEND_AMOUNT,
Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()),
None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn create_and_claim_treasury_spend() {
// create and approve a treasury spend.
assert_ok!(Treasury::spend(
root,
Box::new(asset_kind),
Box::new(pallet_treasury::SpendAsset::Specific(asset_kind)),
SPEND_AMOUNT,
Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()),
None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ fn fellowship_treasury_spend() {
let native_asset = Location::parent();

let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::<Runtime>::spend {
asset_kind: bx!(VersionedLocatableAsset::from((
asset: bx!(pallet_treasury::SpendAsset::Specific(VersionedLocatableAsset::from((
asset_hub_location.clone(),
native_asset.into()
))),
)))),
amount: fellowship_treasury_balance,
beneficiary: bx!(VersionedLocation::from(fellowship_treasury_location)),
valid_from: None,
Expand Down Expand Up @@ -189,10 +189,10 @@ fn fellowship_treasury_spend() {

let fellowship_treasury_spend_call =
RuntimeCall::FellowshipTreasury(pallet_treasury::Call::<Runtime, Instance1>::spend {
asset_kind: bx!(VersionedLocatableAsset::from((
asset: bx!(pallet_treasury::SpendAsset::Specific(VersionedLocatableAsset::from((
asset_hub_location,
native_asset.into()
))),
)))),
amount: fellowship_spend_balance,
beneficiary: bx!(VersionedLocation::from(alice_location)),
valid_from: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ use super::*;
use crate::xcm_config::Collectives;
use frame_support::{
parameter_types,
traits::{tokens::UnityOrOuterConversion, EitherOf, EitherOfDiverse, FromContains},
traits::{
tokens::{asset_ops::common_ops::ConfigurableAssetCategoryManager, UnityOrOuterConversion},
EitherOf, EitherOfDiverse, FromContains,
},
};
use frame_system::EnsureRootWithSuccess;
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
Expand Down Expand Up @@ -132,6 +135,9 @@ pub type TreasuryBalanceConverter = UnityOrOuterConversion<
AssetRate,
>;

pub type AHWAssetCategories =
ConfigurableAssetCategoryManager<AccountId, VersionedLocatableAsset, Balance>;

impl pallet_treasury::Config for Runtime {
type PalletId = TreasuryPalletId;
type Currency = Balances;
Expand All @@ -150,6 +156,7 @@ impl pallet_treasury::Config for Runtime {
type Paymaster = LocalPay<NativeAndAllAssets, TreasuryAccount, xcm_config::LocationToAccountId>;
type BalanceConverter = TreasuryBalanceConverter;
type PayoutPeriod = PayoutSpendPeriod;
type AssetCategories = AHWAssetCategories;
type BlockNumberProvider = RelaychainDataProvider<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = parachains_common::pay::benchmarks::LocalPayArguments<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use cumulus_primitives_core::ParaId;
use frame_support::{
parameter_types,
traits::{
tokens::UnityOrOuterConversion, EitherOf, EitherOfDiverse, FromContains, MapSuccess,
OriginTrait, TryWithMorphedArg,
tokens::{asset_ops::common_ops::ConfigurableAssetCategoryManager, UnityOrOuterConversion},
EitherOf, EitherOfDiverse, FromContains, MapSuccess, OriginTrait, TryWithMorphedArg,
},
PalletId,
};
Expand Down Expand Up @@ -285,6 +285,9 @@ pub type FellowshipTreasuryPaymaster = PayOverXcm<

pub type FellowshipTreasuryInstance = pallet_treasury::Instance1;

pub type CWAssetCategories =
ConfigurableAssetCategoryManager<AccountId, VersionedLocatableAsset, Balance>;

impl pallet_treasury::Config<FellowshipTreasuryInstance> for Runtime {
type WeightInfo = weights::pallet_treasury::WeightInfo<Runtime>;
type PalletId = FellowshipTreasuryPalletId;
Expand Down Expand Up @@ -329,6 +332,7 @@ impl pallet_treasury::Config<FellowshipTreasuryInstance> for Runtime {
AssetRate,
>;
type PayoutPeriod = ConstU32<{ 30 * DAYS }>;
type AssetCategories = CWAssetCategories;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments<
sp_core::ConstU8<1>,
Expand Down
7 changes: 5 additions & 2 deletions polkadot/runtime/common/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use frame_support::traits::{
fungible::{Balanced, Credit},
tokens::imbalance::ResolveTo,
tokens::{asset_ops::common_ops::ConfigurableAssetCategoryManager, imbalance::ResolveTo},
Contains, ContainsPair, Imbalance, OnUnbalanced,
};
use pallet_treasury::TreasuryAccountId;
use polkadot_primitives::Balance;
use polkadot_primitives::{AccountId, Balance};
use sp_runtime::{traits::TryConvert, Perquintill};
use xcm::VersionedLocation;

Expand Down Expand Up @@ -293,6 +293,8 @@ pub mod benchmarks {
}
}

pub type MockAssetCategoryManager = ConfigurableAssetCategoryManager<AccountId, (), u64>;

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -400,6 +402,7 @@ mod tests {
type BalanceConverter = UnityAssetBalanceConversion;
type PayoutPeriod = ConstU64<0>;
type BlockNumberProvider = System;
type AssetCategories = MockAssetCategoryManager;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = ();
}
Expand Down
6 changes: 5 additions & 1 deletion polkadot/runtime/rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use core::cmp::Ordering;
use frame_support::{
dynamic_params::{dynamic_pallet_params, dynamic_params},
traits::FromContains,
traits::{tokens::asset_ops::common_ops::ConfigurableAssetCategoryManager, FromContains},
};
use pallet_balances::WeightInfo;
use pallet_nis::WithMaximumOf;
Expand Down Expand Up @@ -330,6 +330,9 @@ impl EnsureOriginWithArg<RuntimeOrigin, RuntimeParametersKey> for DynamicParamet
}
}

pub type RococoAssetCategories =
ConfigurableAssetCategoryManager<AccountId, VersionedLocatableAsset, Balance>;

impl pallet_scheduler::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type RuntimeEvent = RuntimeEvent;
Expand Down Expand Up @@ -561,6 +564,7 @@ impl pallet_treasury::Config for Runtime {
>;
type PayoutPeriod = PayoutSpendPeriod;
type BlockNumberProvider = System;
type AssetCategories = RococoAssetCategories;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments;
}
Expand Down
13 changes: 9 additions & 4 deletions polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ use frame_support::{
genesis_builder_helper::{build_state, get_preset},
parameter_types,
traits::{
fungible::HoldConsideration, tokens::UnityOrOuterConversion, AsEnsureOriginWithArg,
ConstU32, Contains, EitherOf, EitherOfDiverse, EnsureOriginWithArg, FromContains,
InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, Nothing, ProcessMessage,
ProcessMessageError, VariantCountOf, WithdrawReasons,
fungible::HoldConsideration,
tokens::{asset_ops::common_ops::ConfigurableAssetCategoryManager, UnityOrOuterConversion},
AsEnsureOriginWithArg, ConstU32, Contains, EitherOf, EitherOfDiverse, EnsureOriginWithArg,
FromContains, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, Nothing,
ProcessMessage, ProcessMessageError, VariantCountOf, WithdrawReasons,
},
weights::{ConstantMultiplier, WeightMeter},
PalletId,
Expand Down Expand Up @@ -893,6 +894,9 @@ impl ah_client::SendToAssetHub for StakingXcmToAssetHub {
}
}

pub type WestendAssetCategories =
ConfigurableAssetCategoryManager<AccountId, VersionedLocatableAsset, Balance>;

impl ah_client::Config for Runtime {
type CurrencyBalance = Balance;
type AssetHubOrigin =
Expand Down Expand Up @@ -975,6 +979,7 @@ impl pallet_treasury::Config for Runtime {
>;
type PayoutPeriod = PayoutSpendPeriod;
type BlockNumberProvider = System;
type AssetCategories = WestendAssetCategories;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments;
}
Expand Down
44 changes: 44 additions & 0 deletions prdoc/pr_10381.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: Improve Treasury Payout of Stables

doc:
- audience: Runtime Devs
description: |
This PR introduces category-based treasury spending, allowing the treasury to request payment from a category of assets (e.g., USD* stablecoins) rather than a single specific asset.
On payout, the requested amount is distributed across available assets within that category, optimizing for successful payment execution.

crates:
- name: pallet-treasury
bump: major
- name: frame-support
bump: minor
- name: pallet-assets
bump: minor
- name: pallet-bounties
bump: patch
- name: pallet-child-bounties
bump: patch
- name: pallet-tips
bump: patch
- name: staking-async-parachain-runtime
bump: minor
- name: staking-async-rc-runtime
bump: minor
- name: polkadot-runtime-common
bump: minor
- name: asset-hub-westend-runtime
bump: minor
- name: collectives-westend-runtime
bump: minor
- name: westend-runtime
bump: minor
- name: rococo-runtime
bump: minor
- name: kitchensink-runtime
bump: minor
- name: asset-hub-westend-integration-tests
bump: patch
- name: collectives-westend-integration-tests
bump: patch
28 changes: 27 additions & 1 deletion substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use pallet_multi_asset_bounties::ArgumentsFactory as PalletMultiAssetBountiesArg
use pallet_treasury::ArgumentsFactory as PalletTreasuryArgumentsFactory;
#[cfg(feature = "runtime-benchmarks")]
use polkadot_sdk::sp_core::crypto::FromEntropy;

use polkadot_sdk::*;

use alloc::{vec, vec::Vec};
Expand All @@ -54,6 +53,7 @@ use frame_support::{
Balanced, Credit, HoldConsideration, ItemOf, NativeFromLeft, NativeOrWithId, UnionOf,
},
tokens::{
asset_ops::common_ops::AssetCategoryManager,
imbalance::{ResolveAssetTo, ResolveTo},
nonfungibles_v2::Inspect,
pay::PayAssetFromAccount,
Expand Down Expand Up @@ -266,6 +266,31 @@ impl Contains<RuntimeCallNameOf<Runtime>> for TxPauseWhitelistedCalls {
}
}

pub struct CombinedAssetManager;

impl AssetCategoryManager<AccountId> for CombinedAssetManager {
type AssetKind = NativeOrWithId<u32>;
type Balance = Balance;

fn assets_in_category(category: &[u8]) -> Vec<Self::AssetKind> {
Assets::assets_in_category(category)
.into_iter()
.map(|asset_id| NativeOrWithId::WithId(asset_id))
.collect()
}

fn available_balance(asset: Self::AssetKind, owner: AccountId) -> Option<Self::Balance> {
match asset {
NativeOrWithId::Native => {
Some(Balances::free_balance(&owner))
}
NativeOrWithId::WithId(asset_id) => {
Assets::available_balance(asset_id, owner)
}
}
}
}

#[cfg(feature = "runtime-benchmarks")]
pub struct AssetRateArguments;
#[cfg(feature = "runtime-benchmarks")]
Expand Down Expand Up @@ -1332,6 +1357,7 @@ impl pallet_treasury::Config for Runtime {
type BalanceConverter = AssetRate;
type PayoutPeriod = SpendPayoutPeriod;
type BlockNumberProvider = System;
type AssetCategories = CombinedAssetManager;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = PalletTreasuryArguments;
}
Expand Down
27 changes: 27 additions & 0 deletions substrate/frame/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ use frame_support::{
storage::KeyPrefixIterator,
traits::{
tokens::{
asset_ops::common_ops::AssetCategoryManager,
fungibles, DepositConsequence, Fortitude,
Preservation::{Expendable, Preserve},
WithdrawConsequence,
Expand Down Expand Up @@ -487,6 +488,15 @@ pub mod pallet {
ValueQuery,
>;

#[pallet::storage]
pub type AssetCategories<T: Config<I>, I: 'static = ()> = StorageMap<
_,
Blake2_128Concat,
BoundedVec<u8, ConstU32<32>>, // Category name
BoundedVec<T::AssetId, ConstU32<32>>, // Assets in this category
Comment on lines +495 to +496

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic numbers: I thing it would be good to make them configurable

ValueQuery,
>;

/// The asset ID enforced for the next asset creation, if any present. Otherwise, this storage
/// item has no effect.
///
Expand Down Expand Up @@ -1973,6 +1983,23 @@ pub mod pallet {
Reserves::<T, I>::get(id).into_inner()
}
}

impl<T: Config<I>, I: 'static> AssetCategoryManager<T::AccountId> for Pallet<T, I> {
type AssetKind = T::AssetId;
type Balance = T::Balance;

/// Get all assets in a category
fn assets_in_category(category: &[u8]) -> Vec<Self::AssetKind> {
BoundedVec::<u8, ConstU32<32>>::try_from(category.to_vec())
.map(|bounded_category| AssetCategories::<T, I>::get(bounded_category).into_inner())
.unwrap_or_default()
}

/// Get available balance of a specific asset in treasury
fn available_balance(asset: Self::AssetKind, owner: T::AccountId) -> Option<Self::Balance> {
Self::balance_of(owner, asset)
}
}
}

#[cfg(any(feature = "try-runtime", test))]
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/bounties/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-treasury/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-assets/try-runtime",
"pallet-assets/try-runtime",
"pallet-balances/try-runtime",
"pallet-treasury/try-runtime",
"sp-runtime/try-runtime",
Expand Down
Loading
Loading