referrerpolicy=no-referrer-when-downgrade

Crate pallet_psm

Crate pallet_psm 

Source
Expand description

§Peg Stability Module (PSM) Pallet

Instantiable Peg Stability Modules (PSMs). Each PSM enables 1:1 swaps between an internal stablecoin and one or more approved external stablecoins, typically to maintain a peg.

§Pallet API

See the pallet module for more information about the interfaces this pallet exposes, including its configuration trait, dispatchables, storage items, events and errors.

§Terminology

Throughout this pallet two distinct token roles are referenced:

  • Internal — the stablecoin a PSM issues and burns (e.g. a runtime’s own USD-pegged stablecoin). Each PSM instance is keyed by its internal asset id; multiple instances can coexist, each with its own reserve, debt ceiling, fee destination and approved externals. Mint operations credit the user with the internal asset; redeem operations burn it. Fees are collected in the internal asset and forwarded to that instance’s PsmInfo::fee_destination.
  • External — third-party assets (e.g. USDC, USDT) approved on a specific PSM via Pallet::add_external_asset and held in that PSM’s reserve. Users deposit external to mint internal, and burn internal to redeem external. A PSM may approve multiple externals, each identified by external_asset.

§Overview

A PSM strengthens its internal asset’s peg by providing arbitrage opportunities:

  • When the internal asset trades above $1: Users swap external assets for the internal asset and sell for profit.
  • When the internal asset trades below $1: Users buy cheap internal asset and swap for external assets.

This creates a price corridor bounded by the minting and redemption fees.

§Key Concepts

  • PSM instance: A configured Peg Stability Module, keyed by its internal asset id and described by PsmInfo. Each instance has its own reserve account derived from blake2_256((PalletId::TYPE_ID, PalletId, internal_asset).encode()).
  • Minting: Deposit external asset → receive internal asset (minus fee).
  • Redemption: Burn internal asset → receive external asset (minus fee).
  • Reserve: External asset balance held by a PSM’s reserve account (derived, not stored).
  • PSM Debt: Total internal asset minted through a PSM, backed 1:1 by external assets in that PSM’s reserve.
  • Circuit Breaker: Per-external emergency control to disable minting or all swaps.

§Storage Invariants

With the try-runtime feature, the pallet tests seventeen storage invariants in each block. The function do_try_state does these tests. It confirms that:

  • each decimals snapshot agrees with the live asset metadata;
  • each reserve covers the debt that the PSM records against it;
  • the issuance of the internal asset covers the debt of the instance;
  • no storage row stays after the removal of its PSM;
  • no debt exists for a pair that the PSM does not approve.

Five of the seventeen checks are advisory. An advisory check writes a warning to the log. It does not return an error. A permitted action can create these five states, so an error would stop the chain after a correct call:

  • debt above a per-asset ceiling;
  • debt above the ceiling of an instance;
  • a reserve with a balance, but with zero weight and zero debt;
  • live decimals of the internal asset that differ from the recorded value;
  • live decimals of an external asset that differ from the recorded value.

The two decimal checks are advisory because an asset owner can change asset metadata at any time, and swaps use the recorded values. Drift does not change the arithmetic of the pallet. It changes what a reader of live metadata sees.

§Fee Structure

  • Minting Fee (MintingFee): Deducted from internal-asset output during minting, configured per (internal_asset, external_asset) pair.
  • Redemption Fee (RedemptionFee): Deducted from external-asset output during redemption, configured per (internal_asset, external_asset) pair.

Fees are collected in the internal asset and transferred to the instance’s PsmInfo::fee_destination.

§Example

ⓘ
// Mint internal asset by depositing USDC on the PSM
let max_fee = MintingFee::<Runtime>::get(INTERNAL_ASSET_ID, USDC_ASSET_ID);
Psm::mint(
	RuntimeOrigin::signed(user),
	INTERNAL_ASSET_ID,
	USDC_ASSET_ID,
	1000 * UNIT,
	max_fee,
)?;

// Redeem USDC by burning the internal asset
let max_fee = RedemptionFee::<Runtime>::get(INTERNAL_ASSET_ID, USDC_ASSET_ID);
Psm::redeem(
	RuntimeOrigin::signed(user),
	INTERNAL_ASSET_ID,
	USDC_ASSET_ID,
	1000 * UNIT,
	max_fee,
)?;

Re-exports§

pub use weights::WeightInfo;
pub use pallet::*;

Modules§

pallet
The pallet module in each FRAME pallet hosts the most important items needed to construct this pallet.
weights
Autogenerated weights for pallet_psm

Traits§

BenchmarkHelper
Helper trait for benchmark setup.