Polkadot Release Analysis v0.9.40

Polkadot Release Analysis v0.9.40

:warning: The following report is not an exhaustive list of changes included in the release, but a set of changes that we felt deserved to be highlighted due to their impact on the Polkadot ecosystem builders.

Please do not stop reading the release notes v0.9.40. This report is complementary to the changelogs, not a replacement.

Highlights are categorized into High Impact, Medium Impact, and Low Impact for ease of navigation.
Also there is a section related to all note worthy changes related to tooling integration.

Help us improve the release analysis by filling out this 6 question survey.


In this release we can find a variety of very interesting changes, barriers within XCM configuration will now leverage a new Matcher API, pallet-nfts is receiving a new permission model along with new features for assets and nomination pools among other changes.

Runtimes built on release v0.9.40

  • Rococo v9400
  • Westend v9400
  • Kusama v9400
  • Polkadot v9400

:hammer_and_wrench: Tooling Section

:exclamation: High Impact

Introduce XCM matcher for writing barriers

PR: Introduce XCM matcher for writing barriers by KiChjang · Pull Request #6756 · paritytech/polkadot · GitHub
Related PR: XCM: Use matcher API in DenyReserveAssetTransferToRelay by KiChjang · Pull Request #2290 · paritytech/cumulus · GitHub
Related Issues:
Consider a declarative API to describe XCM barrier conditions · Issue #4276 · paritytech/polkadot · GitHub

Why is this change interesting for builders?

With XCM, Polkadot enables secure cross-chain exchange of any type of data. However a cross-chain message needs to be whitelisted in the receiver end to be accepted. The whitelisting happens in a place called the Barrier. Barriers are a set of filters to statically accept or reject XCM messages.

This PR introduces a new API fn matchers() for &mut [Instructions<Call>] that is similar to iterators: it can advance the current instruction to the next while ensuring the current instruction matches/fulfills a certain condition; it can assert the remaining number of instructions left to process; and it can also skip instructions while a condition is being evaluated as true.

The main purpose of creating a Matcher API instead of using iterators is that of purpose and clarity – it is much easier to maintain, audit and write matchers over iterators, as they are intended to be declarative in nature.

Here is an example for how the matcher can be implemented on Statemint/e where it should filter reserve transfer from the relay chain:

// See issue <https://github.com/paritytech/polkadot/issues/5233>
pub struct DenyReserveTransferToRelayChain;
impl ShouldExecute for DenyReserveTransferToRelayChain {
	fn should_execute<RuntimeCall>(
		origin: &MultiLocation,
		message: &mut [Instruction<RuntimeCall>],
		_max_weight: Weight,
		_weight_credit: &mut Weight,
	) -> Result<(), ()> {
			|_| true,
			|inst| match inst {
				InitiateReserveWithdraw {
					reserve: MultiLocation { parents: 1, interior: Here },
				} |
				DepositReserveAsset {
					dest: MultiLocation { parents: 1, interior: Here }, ..
				} |
				TransferReserveAsset {
					dest: MultiLocation { parents: 1, interior: Here }, ..
				} => {
					Err(()) // Deny
				// An unexpected reserve transfer has arrived from the Relay Chain. Generally,
				// `IsReserve` should not allow this, but we just log it here.
				ReserveAssetDeposited { .. }
					if matches!(origin, MultiLocation { parents: 1, interior: Here }) =>
						target: "xcm::barrier",
						"Unexpected ReserveAssetDeposited from the Relay Chain",
				_ => Ok(ControlFlow::Continue(())),

		// Permit everything else

:warning: Medium Impact

[NFTs] Rework permissions model

PR: [NFTs] Rework permissions model by jsidorenko · Pull Request #13482 · paritytech/substrate · GitHub

Why is this important?

This PR introduces changes to the permissions model in the pallet-nfts, a collection of non-fungible tokens. The Admin account will no longer be able to transfer or burn items it doesn’t own, and to destroy the collection, there should be zero items left. Some actions were moved from one role to another to simplify accounts management, particularly for complex collections where each role represents a separate service with its own responsibilities.

The Owner can destroy the collection, redeposit, set the team, set the collection max supply, and lock the collection. Admin can set attributes and metadata, lock item properties, and perform actions that were moved from the Owner role. Freezer can lock and unlock item transfer. Issuer can mint tokens, force mint with custom item configuration, update mint settings, and perform actions that were moved from the Owner role.

Why is this change interesting for builders?
The changes introduced in this PR are interesting for builders because they make it easier to create complex non-fungible token collections with multiple roles and responsibilities. The improved security and account management features provide builders with more flexibility and control over their collections.responsibilities.

Yieldable queues for pallet MessageQueue

PR: https://github.com/paritytech/substrate/pull/13424

Why is this important?

Introduces a new variant to ProcessMessageError enum, with it a queue hints the message processor to cease servicing this queue and proceed to the next one.

A new implementation for ServiceQueues, NoopServiceQueues that will service queues by doing nothing. We can see the reason for this in the PR description itself.

ServiceQueues cannot be implemented for () due to its associated type.

Lastly, fn process_message in pub trait ProcessMessage sees its signature changed, using now a &mut WeightMeter instead of Weight, and only returning whether the message was processed.

fn process_message(
    message: &[u8],
    origin: Self::Origin,
-   weight_limit: Weight,
+   meter: &mut WeightMeter,
- ) -> Result<(bool, Weight), ProcessMessageError>;
+ ) -> Result<bool, ProcessMessageError>;

Why is this change interesting for builders?

:warning: The changes made to ProcessMessageError and ProcessMessage are breaking changes, we have not being able to identify any usage of this pallet downstream and that is why these changes come with no migrations, but if you do, please migrate consequently.

:information_source: Low Impact

Assets pallet: Giving the asset owner the ability to set minimum balance

PR: https://github.com/paritytech/substrate/pull/13486

Why is this change interesting for builders?
At the moment, there is no way to set minimum balance of an asset by asset owner. However there is a workaround by setting through force_asset_status extrinsic but this requires ForceOrigin.

As a part of this PR, Asset pallet has introduced a new extrinsic set_min_balance to set minimum balance by asset owner. This extrinsic still has some limitations. This extrinsic will only be allowed if:

  • If there is no account holding the asset
  • If new min balance is less than the old one
  • If the asset is not marked as sufficient

Does this change have a related companion PR?
Cumulus companion PR: Companion for #13486 by Szegoo · Pull Request #2253 · paritytech/cumulus · GitHub

Related Issues:

Related PR:

Pub enum runtime to pub struct runtime

PR: Pub enum runtime to pub struct runtime by a-moreira · Pull Request #13250 · paritytech/substrate · GitHub

Why is this change interesting for builders?
Even though construct_runtime! macro accepts both structs and enums at the moment, this PR substitutes all pub enum Runtime declarations with pub struct Runtime in the sake of having a clearer code base.
This is not a breaking change, but please understand this change and apply it as a good practice in your runtime.

Nomination Pool Commission

PR: https://github.com/paritytech/substrate/pull/13128

Why is this important?
With these changes nomination pools receive new functionality, commissions.
A pool can optionally have a commission configuration, via the root role, set with set_commission and claimed with claim_commission. A payee account must be supplied with the desired commission percentage. Beyond the commission itself, a pool can have a maximum commission and a change rate.
Importantly, both max commission set_commission_max and change rate
set_commission_change_rate can not be removed once set, and can only be set to more restrictive values (i.e. a lower max commission or a slower change rate) in subsequent updates.

This is how the new elements look like:

pub struct Commission<T: Config> {
	/// Optional commission rate of the pool along with the account commission is paid to.
	pub current: Option<(Perbill, T::AccountId)>,
	/// Optional maximum commission that can be set by the pool `root`. Once set, this value can
	/// only be updated to a decreased value.
	pub max: Option<Perbill>,
	/// Optional configuration around how often commission can be updated, and when the last
	/// commission update took place.
	pub change_rate: Option<CommissionChangeRate<T::BlockNumber>>,
	/// The block from where throttling should be checked from. This value will be updated on all
	/// commission updates and when setting an initial `change_rate`.
	pub throttle_from: Option<T::BlockNumber>,
pub struct CommissionChangeRate<BlockNumber> {
	/// The maximum amount the commission can be updated by per `min_delay` period.
	pub max_increase: Perbill,
	/// How often an update can take place.
	pub min_delay: BlockNumber,
/// The maximum commission that can be charged by a pool. Used on commission payouts to bound
/// pool commissions that are > `GlobalMaxCommission`, necessary if a future
/// `GlobalMaxCommission` is lower than some current pool commissions.
pub type GlobalMaxCommission<T: Config> = StorageValue<_, Perbill, OptionQuery>;    

The following extrinsics are available for the root role of a nomination pool to dispatch:

Participate in the discussion on which values should GlobalMaxCommission have in the related Polkadot forum post.

Salary pallet (#13378)

PR: Salary pallet by gavofyork · Pull Request #13378 · paritytech/substrate · GitHub

Why is this change interesting for builders?
A new pallet has been released that allows for periodic payments to members of a ranked collective according to rank.

There are some interesting features such as a “budget” (the total budget per cycle) and setting up a “paymaster” (means by which we can make payments to the account). You can see an example configuration here where the budget and paymaster are configured as the following:

parameter_types! {
	pub const Budget: Balance = 10_000 * DOLLARS;
	pub TreasuryAccount: AccountId = Treasury::account_id();
impl pallet_salary::Config for Runtime {
	type WeightInfo = ();
	type RuntimeEvent = RuntimeEvent;
	type Paymaster = pallet_salary::PayFromAccount<Balances, TreasuryAccount>;
	type Members = RankedCollective;
	type Salary = SalaryForRank;
	type RegistrationPeriod = ConstU32<200>;
	type PayoutPeriod = ConstU32<200>;
	type Budget = Budget;

You can read the code for the salary pallet here.

Return account’s asset balances

PR: Return account's asset balances by jsidorenko · Pull Request #13352 · paritytech/substrate · GitHub

Why is this change interesting for builders?

As a part of this PR, Asset pallet has introduced a new RPC end point account_balances which will return all asset ids with their corresponding balance for an associated account.

Does this change have a related companion PR?
Cumulus companion PR: https://github.com/paritytech/cumulus/pull/2180

Metadata V15: Expose pallet documentation

PR: https://github.com/paritytech/substrate/pull/13452

Why is this important?

This patch adds the functionality to include pallet documentation in the runtime metadata. Pallet documentation can be defined in different ways such as a doc string, including an external file or including the documentation using the pallet_doc attribute. This new feature allows developers to provide a more detailed description of the pallets, making it easier for other developers to understand and use the pallets. The documentation is included in the runtime metadata and is expanded on the pallet module. Unlike the doc attribute, which is inserted at the beginning of the module, the documentation provided to the pallet_doc attribute is not. This new functionality has been added to the final metadata V15 PR and has been tested in unit tests, UI tests, and subxt. This is important for Polkadot builders because it will make it easier for them to understand the functionality of different pallets, reducing development time and increasing the interoperability of different components.

Code Snippets

/// Documentation for pallet 1
#[doc = "Documentation for pallet 2"]
#[doc = include_str!("../README.md")]
pub struct Pallet<T>(_); 

In case you missed the analysis from the previous release (v0.9.39):