Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7374bad
feat: rebase onto master directly
lrazovic Mar 20, 2026
e7df82e
Merge branch 'master' into leo/psm
lrazovic Mar 20, 2026
eea3765
chore: simplify the imports
lrazovic Mar 20, 2026
536e7c3
feat: remove `StableAssetId` and use the new `fungible::Create`
lrazovic Mar 20, 2026
3138b93
doc: align the README to the latest changes
lrazovic Mar 20, 2026
1eca095
chore: check if min balance > 0
lrazovic Mar 23, 2026
26f3b9a
chore: add prdoc
lrazovic Mar 23, 2026
241e839
feat: re-introduce the `BenchmarkHelper`
lrazovic Mar 24, 2026
8266af1
feat: check the decimals of the new asser
lrazovic Mar 24, 2026
fa4f31b
feat: simplify the migration
lrazovic Mar 24, 2026
01c3c0b
feat: use a `CountedStorageMap`
lrazovic Mar 24, 2026
c6c8c60
feat: restore the `FeeDestination` approach
lrazovic Mar 24, 2026
94b74bd
Update substrate/frame/psm/src/tests.rs
lrazovic Mar 31, 2026
b61a6e0
Update substrate/frame/psm/src/tests.rs
lrazovic Mar 31, 2026
880d46f
Update substrate/frame/psm/src/lib.rs
lrazovic Mar 31, 2026
a0b92fd
Update substrate/frame/psm/src/lib.rs
lrazovic Mar 31, 2026
4950ae9
chore: use parameter_types + static
lrazovic Mar 31, 2026
2c769ae
chore: fix the assert_noop syntax
lrazovic Mar 31, 2026
4831e74
feat: remove `VaultsInterface` and use the simpler `MaximumIssuance`
lrazovic Mar 31, 2026
def4986
chore: add permissions helpers
lrazovic Mar 31, 2026
811e669
feat: add `try-runtime` checks
lrazovic Mar 31, 2026
424ac6f
chore: restrict visibility
lrazovic Mar 31, 2026
f5a596a
chore: restrict visibility, take 2
lrazovic Mar 31, 2026
a54a32e
feat: more defensive cheks
lrazovic Mar 31, 2026
14c2714
feat: relax can_set_asset_ceiling
lrazovic Apr 1, 2026
8475fb4
tests: add mint_ops to ExtBuilder
lrazovic Apr 1, 2026
dae84b5
feat: use UncheckedMigrate pattern
lrazovic Apr 1, 2026
0392706
tests: address feedback
lrazovic Apr 1, 2026
c4d7de6
Merge branch 'master' into leo/psm
lrazovic Apr 1, 2026
513751e
tests: run do_try_state in the mock
lrazovic Apr 1, 2026
9a4e883
doc: clarify manager level rights
lrazovic Apr 1, 2026
e40a9b3
chore: markdown lint
lrazovic Apr 1, 2026
d226b43
chore: adjust ratio vs weight terminology
lrazovic Apr 1, 2026
f4e1111
tests: add new test to check what happens when setting weight to 0%
lrazovic Apr 1, 2026
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
17 changes: 17 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ members = [
"substrate/frame/people",
"substrate/frame/preimage",
"substrate/frame/proxy",
"substrate/frame/psm",
"substrate/frame/ranked-collective",
"substrate/frame/recovery",
"substrate/frame/referenda",
Expand Down Expand Up @@ -1039,6 +1040,7 @@ pallet-parameters = { path = "substrate/frame/parameters", default-features = fa
pallet-people = { path = "substrate/frame/people", default-features = false }
pallet-preimage = { path = "substrate/frame/preimage", default-features = false }
pallet-proxy = { path = "substrate/frame/proxy", default-features = false }
pallet-psm = { path = "substrate/frame/psm", default-features = false }
pallet-ranked-collective = { path = "substrate/frame/ranked-collective", default-features = false }
pallet-recovery = { path = "substrate/frame/recovery", default-features = false }
pallet-referenda = { path = "substrate/frame/referenda", default-features = false }
Expand Down
26 changes: 26 additions & 0 deletions prdoc/pr_11068.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
title: 'FRAME: Add Peg Stability Module (PSM) pallet'
doc:
- audience: Runtime Dev
description: |-
Introduces `pallet-psm`, a Peg Stability Module that enables 1:1 swaps between a native
stablecoin (pUSD) and pre-approved external stablecoins (e.g. USDC, USDT). The PSM
strengthens the stablecoin peg by creating arbitrage opportunities bounded by configurable
minting and redemption fees.

Key features:
- Minting: deposit an external stablecoin to receive pUSD
- Redemption: burn pUSD to receive an external stablecoin
- Per-asset circuit breakers to disable minting or all swaps
- Configurable ceiling weights and maximum PSM debt ratio
- Inter-pallet traits (`VaultsInterface`, `PsmInterface`) for coordinating debt ceilings
with a companion Vaults pallet

crates:
- name: pallet-psm
bump: major
- name: kitchensink-runtime
bump: major
- name: frame-support
bump: minor
- name: polkadot-sdk
bump: minor
63 changes: 63 additions & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,9 @@ mod runtime {
#[runtime::pallet_index(85)]
pub type Oracle = pallet_oracle::Pallet<Runtime>;

#[runtime::pallet_index(86)]
pub type Psm = pallet_psm::Pallet<Runtime>;

#[runtime::pallet_index(89)]
pub type MetaTx = pallet_meta_tx::Pallet<Runtime>;

Expand Down Expand Up @@ -3062,6 +3065,65 @@ impl pallet_oracle::Config for Runtime {
type BenchmarkHelper = OracleBenchmarkingHelper;
}

parameter_types! {
/// The pUSD stablecoin asset ID.
pub const PsmStablecoinAssetId: u32 = 4242;
/// Minimum swap amount for PSM operations (100 pUSD = 100 * 10^6).
pub const PsmMinSwapAmount: Balance = 100_000_000;
/// PalletId for deriving the PSM system account.
pub const PsmPalletId: PalletId = PalletId(*b"py/pegsm");
/// Insurance fund account that receives PSM fee revenue.
pub PsmInsuranceFundAccount: AccountId =
sp_runtime::traits::AccountIdConversion::<AccountId>::into_account_truncating(
&PalletId(*b"py/insur"),
);
}

type PsmStableAsset = ItemOf<Assets, PsmStablecoinAssetId, AccountId>;

/// Stub VaultsInterface that imposes no debt ceiling.
pub struct NoVaultsCeiling;
impl frame_support::traits::VaultsInterface for NoVaultsCeiling {
type Balance = Balance;
fn get_maximum_issuance() -> Balance {
Balance::MAX
}
}

/// EnsureOrigin implementation for PSM management that supports privilege levels.
pub struct EnsurePsmManager;
impl frame_support::traits::EnsureOrigin<RuntimeOrigin> for EnsurePsmManager {
type Success = pallet_psm::PsmManagerLevel;

fn try_origin(o: RuntimeOrigin) -> Result<Self::Success, RuntimeOrigin> {
use frame_system::RawOrigin;

match o.clone().into() {
Ok(RawOrigin::Root) => Ok(pallet_psm::PsmManagerLevel::Full),
_ => Err(o),
}
}

#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<RuntimeOrigin, ()> {
Ok(RuntimeOrigin::root())
}
}

/// Configure the PSM (Peg Stability Module) pallet.
impl pallet_psm::Config for Runtime {
type Fungibles = Assets;
type AssetId = u32;
type VaultsInterface = NoVaultsCeiling;
type ManagerOrigin = EnsurePsmManager;
type WeightInfo = pallet_psm::weights::SubstrateWeight<Runtime>;
type StableAsset = PsmStableAsset;
type FeeHandler = ResolveTo<PsmInsuranceFundAccount, PsmStableAsset>;
type PalletId = PsmPalletId;
type MinSwapAmount = PsmMinSwapAmount;
type MaxExternalAssets = ConstU32<10>;
}

/// MMR helper types.
mod mmr {
use super::*;
Expand Down Expand Up @@ -3207,6 +3269,7 @@ mod benches {
[pallet_asset_conversion_ops, AssetConversionMigration]
[pallet_verify_signature, VerifySignature]
[pallet_meta_tx, MetaTx]
[pallet_psm, Psm]
);
}

Expand Down
58 changes: 58 additions & 0 deletions substrate/frame/psm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[package]
name = "pallet-psm"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
description = "FRAME pallet for the Peg Stability Module."
readme = "README.md"
include = ["README.md", "src/**/*"]

[lints]
workspace = true

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { features = ["derive"], workspace = true }
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
log = { workspace = true }
scale-info = { features = ["derive"], workspace = true }
sp-runtime = { workspace = true }

[dev-dependencies]
pallet-assets = { workspace = true, default-features = true }
pallet-balances = { workspace = true, default-features = true }
sp-io = { workspace = true, default-features = true }

[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"log/std",
"scale-info/std",
"sp-runtime/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-assets/try-runtime",
"pallet-balances/try-runtime",
"sp-runtime/try-runtime",
]
Loading