Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
56671cb
feat: upstream pallet-vaults
lrazovic Dec 19, 2025
49b0ae0
chore: removed deprecated warning on SubstrateWeight.
lrazovic Dec 19, 2025
054c6e6
chore: first feedback round
lrazovic Jan 5, 2026
c31d1b1
Merge branch 'master' into leo/vaults
lrazovic Jan 5, 2026
711b0b8
Merge branch 'leo/vaults' of github.com:amforc/polkadot-sdk into leo/…
lrazovic Jan 5, 2026
65030aa
feat: remove on_runtime_upgrade hook from the pallet
lrazovic Jan 5, 2026
8d87807
chore: move the closing logic into the do_close_vault
lrazovic Jan 5, 2026
ff5479b
chore: fix typo
lrazovic Jan 5, 2026
f41e606
feat: initial bechmark helper implementation
lrazovic Jan 12, 2026
be3b6c9
Merge branch 'master' into leo/vaults
lrazovic Jan 23, 2026
538c5b6
Merge branch 'leo/vaults' of github.com:amforc/polkadot-sdk into leo/…
lrazovic Jan 23, 2026
3694f61
feat: v1 initilizer migration
lrazovic Jan 23, 2026
9acbc8d
feat: introduce the `DebtComponents`
lrazovic Jan 23, 2026
2bf2d38
feat: align with latest design doc version
lrazovic Jan 23, 2026
38eb725
chore: let's be pedantic
lrazovic Jan 23, 2026
2b65c6d
fix: update function name
lrazovic Jan 23, 2026
9d8633c
fix: add ensure_max_position_amount in benchmarks
lrazovic Jan 23, 2026
77a0d86
chore: remove redundant tests
lrazovic Jan 23, 2026
10e805b
chore: add missing documentation on events
lrazovic Jan 23, 2026
a6e1ee0
chore: introduce the do_mint abstraction
lrazovic Jan 26, 2026
bca8dfc
feat: move all the parameters to storage
lrazovic Jan 26, 2026
ef7d15c
chore: fmt
lrazovic Jan 26, 2026
05a1fb5
feat: simplify the benchmark helper
lrazovic Jan 26, 2026
b9f9c18
chore: restore Cargo.lock
lrazovic Jan 26, 2026
68faafc
chore: add the new storage-based config items to the migration
lrazovic Jan 26, 2026
dc9719f
test: add migration test case
lrazovic Jan 26, 2026
b4d47f0
Merge branch 'master' into leo/vaults
lrazovic Feb 3, 2026
180af26
doc: Update README to align with the latest code changes
lrazovic Feb 4, 2026
aae9eca
feat: add missing set_max_position_amount benchmark
lrazovic Feb 4, 2026
27f543b
chore: fix calls order
lrazovic Feb 4, 2026
2b6abeb
Merge branch 'master' into leo/vaults
lrazovic Feb 4, 2026
547143d
chore: add header license
lrazovic Feb 5, 2026
b9ab9c3
chore: rename from Inner to VersionUnchecked
lrazovic Feb 5, 2026
b865c44
feat: specify principal and interest in the repaid event
lrazovic Feb 5, 2026
53345d3
chore: fmt
lrazovic Feb 5, 2026
a88206f
feat: parameters are now `OptionQuery`s
lrazovic Feb 11, 2026
27bf893
feat: introduce `integrity_test` and `try-state` hooks
lrazovic Feb 11, 2026
16d6cb9
chore: propagate features via zepeter
lrazovic Feb 11, 2026
c6f0696
chore: fix the markdown lint
lrazovic Feb 11, 2026
fd48e0a
feat: use `DefensiveSaturating`
lrazovic Feb 11, 2026
2ff40a0
feat: remove `new` from `DebtComponents`
lrazovic Feb 11, 2026
9d79ff8
tests: invariants do_try_state
lrazovic Feb 11, 2026
0754c19
tests: improve test coverage
lrazovic Feb 11, 2026
3e56060
chore: use ItemOf to represent the pUSD
lrazovic Mar 9, 2026
2831917
feat: let's be polite
lrazovic Mar 9, 2026
f1a9638
feat: accrual interest only if unit
lrazovic Mar 9, 2026
2d8e3ec
feat: heal the best effort
lrazovic Mar 9, 2026
cdb14d6
feat: heal extrinsic is now "free"
lrazovic Mar 9, 2026
61fd9e7
feat: liquidate_vault "free" if successful
lrazovic Mar 9, 2026
3fe62bf
feat: reduce CLA iff prinipal paid is not zero
lrazovic Mar 9, 2026
389590f
feat: liquidate_vault is now transactional
lrazovic Mar 10, 2026
7f9f3bd
feat: track bad debt as principal + interest
lrazovic Mar 10, 2026
e476d9b
test: add mcr raising test
lrazovic Mar 10, 2026
6d4abde
bench: compute `safe_mint_amount` using `MinimumMint`
lrazovic Mar 10, 2026
6cef850
chore: rename to `Collateral` and `StableAsset`
lrazovic Mar 19, 2026
755c773
bench: worst-case for `mint` and `withdraw`
lrazovic Mar 19, 2026
1868737
feat: free `heal` only if successful
lrazovic Mar 19, 2026
97d0989
feat: store the `PreviousStabilityFee`
lrazovic Mar 19, 2026
ae5aa00
chore: generate the weights
lrazovic Mar 19, 2026
f9487d6
Merge branch 'master' into leo/vaults
lrazovic Mar 22, 2026
8f02ed4
chore: move traits to `frame_support`
lrazovic Mar 22, 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
30 changes: 30 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ members = [
"substrate/frame/tx-pause",
"substrate/frame/uniques",
"substrate/frame/utility",
"substrate/frame/vaults",
"substrate/frame/verify-signature",
"substrate/frame/vesting",
"substrate/frame/whitelist",
Expand Down Expand Up @@ -517,6 +518,7 @@ members = [
"substrate/primitives/npos-elections/fuzzer",
"substrate/primitives/offchain",
"substrate/primitives/panic-handler",
"substrate/primitives/pusd",
"substrate/primitives/rpc",
"substrate/primitives/runtime",
"substrate/primitives/runtime-interface",
Expand Down Expand Up @@ -1079,6 +1081,7 @@ pallet-treasury = { path = "substrate/frame/treasury", default-features = false
pallet-tx-pause = { default-features = false, path = "substrate/frame/tx-pause" }
pallet-uniques = { path = "substrate/frame/uniques", default-features = false }
pallet-utility = { path = "substrate/frame/utility", default-features = false }
pallet-vaults = { path = "substrate/frame/vaults", default-features = false }
pallet-verify-signature = { path = "substrate/frame/verify-signature", default-features = false }
pallet-vesting = { path = "substrate/frame/vesting", default-features = false }
pallet-whitelist = { path = "substrate/frame/whitelist", default-features = false }
Expand Down Expand Up @@ -1356,6 +1359,7 @@ sp-mmr-primitives = { path = "substrate/primitives/merkle-mountain-range", defau
sp-npos-elections = { path = "substrate/primitives/npos-elections", default-features = false }
sp-offchain = { path = "substrate/primitives/offchain", default-features = false }
sp-panic-handler = { path = "substrate/primitives/panic-handler", default-features = false }
sp-pusd = { path = "substrate/primitives/pusd", default-features = false }
sp-rpc = { path = "substrate/primitives/rpc", default-features = false }
sp-runtime = { path = "substrate/primitives/runtime", default-features = false }
sp-runtime-interface = { path = "substrate/primitives/runtime-interface", default-features = false }
Expand Down
135 changes: 134 additions & 1 deletion substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use pallet_treasury::ArgumentsFactory as PalletTreasuryArgumentsFactory;
#[cfg(feature = "runtime-benchmarks")]
use polkadot_sdk::sp_core::crypto::FromEntropy;

use polkadot_sdk::*;
use polkadot_sdk::{cumulus_primitives_core::Location, *};

use alloc::{vec, vec::Vec};
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
Expand Down Expand Up @@ -2865,6 +2865,9 @@ mod runtime {
#[runtime::pallet_index(85)]
pub type Oracle = pallet_oracle::Pallet<Runtime>;

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

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

Expand Down Expand Up @@ -3040,6 +3043,136 @@ impl pallet_oracle::Config for Runtime {
type BenchmarkHelper = OracleBenchmarkingHelper;
}

parameter_types! {
/// The pUSD stablecoin asset ID.
pub const VaultsStablecoinAssetId: u32 = 1;
/// Minimum collateral deposit to create a vault (1 DOT = 10^10 planck).
pub const VaultsMinimumDeposit: Balance = 10_000_000_000;
/// Minimum mint amount: 5 pUSD (pUSD has 6 decimals, so 5_000_000).
pub const VaultsMinimumMint: Balance = 5_000_000;
/// Duration (milliseconds) before a vault is considered stale for on_idle fee accrual.
/// 4 hours = 4 × 60 × 60 × 1000 = 14,400,000 ms
pub const VaultsStaleThreshold: u64 = 14_400_000;
/// Maximum age (milliseconds) of oracle price before operations are paused.
/// 1 hour = 60 × 60 × 1000 = 3,600,000 ms
pub const VaultsOracleStalenessThreshold: u64 = 3_600_000;
/// DOT collateral location.
pub VaultsCollateralLocation: Location = Location::here();
}

/// Insurance fund account that receives protocol revenue (interest and penalties).
pub struct InsuranceFundAccount;
impl frame_support::traits::Get<AccountId> for InsuranceFundAccount {
fn get() -> AccountId {
// Use a deterministic insurance fund account
sp_runtime::traits::AccountIdConversion::<AccountId>::into_account_truncating(
&frame_support::PalletId(*b"py/insur"),
)
}
}

/// Mock oracle adapter that provides a fixed price for now.
///
/// This adapter implements `ProvidePrice` with a hardcoded DOT price.
/// For production, replace this with a real oracle integration.
///
/// **Price format (normalized):** smallest_pUSD_units / smallest_collateral_unit
///
/// Example calculation for DOT at $4.21:
/// - DOT has 10 decimals, pUSD has 6 decimals
/// - 1 DOT = 4.21 pUSD
/// - Normalized price = 4.21 × 10^6 / 10^10 = 0.000421
/// - As FixedU128 (18 decimals): 0.000421 × 10^18 = 421_000_000_000_000
pub struct MockOracleAdapter;
impl pallet_vaults::ProvidePrice for MockOracleAdapter {
type Price = FixedU128;
type Moment = u64;

fn get_price(asset: &Location) -> Option<(Self::Price, Self::Moment)> {
// Only support DOT (native asset) for now
if *asset != Location::here() {
return None;
}

// Fixed DOT price: $4.21 normalized for DOT (10 decimals) and pUSD (6 decimals)
// Price = 4.21 * 10^6 / 10^10 = 0.000421
// As FixedU128: 421_000_000_000_000 (0.000421 * 10^18)
let price = FixedU128::from_inner(421_000_000_000_000);

// Use current timestamp from the Timestamp pallet
let now = <Timestamp as frame_support::traits::Time>::now();

Some((price, now))
}
}

/// Stub implementation for the Auctions handler.
///
/// This is a placeholder until a proper Auctions pallet is implemented.
/// Currently, liquidations will fail with `Unimplemented` error.
///
/// TODO: Replace with actual pallet_auctions integration when available.
pub struct AuctionAdapter;
impl pallet_vaults::AuctionsHandler<AccountId, Balance> for AuctionAdapter {
fn start_auction(
_vault_owner: &AccountId,
_collateral_amount: Balance,
_principal: Balance,
_accrued_interest: Balance,
_penalty: Balance,
_keeper: &AccountId,
) -> Result<u32, frame_support::pallet_prelude::DispatchError> {
// TODO: Implement actual auction logic when pallet_auctions is available
// For now, liquidations are disabled
Err(frame_support::pallet_prelude::DispatchError::Other("Auctions not yet implemented"))
}
}

/// EnsureOrigin implementation for vaults management that supports privilege levels.
///
/// - Root origin → `VaultsManagerLevel::Full` (can modify all parameters)
///
/// TODO: In the future, this can be extended to support Emergency privilege level
/// via a (new) specific governance origin that can only lower the debt ceiling.
pub struct EnsureVaultsManager;
impl frame_support::traits::EnsureOrigin<RuntimeOrigin> for EnsureVaultsManager {
type Success = pallet_vaults::VaultsManagerLevel;

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

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

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

/// Configure the Vaults pallet.
impl pallet_vaults::Config for Runtime {
type Currency = Balances;
type RuntimeHoldReason = RuntimeHoldReason;
type Asset = Assets;
type AssetId = u32;
type StablecoinAssetId = VaultsStablecoinAssetId;
type InsuranceFund = InsuranceFundAccount;
type MinimumDeposit = VaultsMinimumDeposit;
type MinimumMint = VaultsMinimumMint;
type TimeProvider = Timestamp;
type ManagerOrigin = EnsureVaultsManager;
type StaleVaultThreshold = VaultsStaleThreshold;
type OracleStalenessThreshold = VaultsOracleStalenessThreshold;
type Oracle = MockOracleAdapter;
type CollateralLocation = VaultsCollateralLocation;
type AuctionsHandler = AuctionAdapter;
type WeightInfo = pallet_vaults::weights::SubstrateWeight<Runtime>;
}

/// MMR helper types.
mod mmr {
use super::*;
Expand Down
65 changes: 65 additions & 0 deletions substrate/frame/vaults/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
[package]
name = "pallet-vaults"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
description = "FRAME pallet for Vaults."
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-pusd = { workspace = true }
sp-runtime = { workspace = true }
xcm = { 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-pusd/std",
"sp-runtime/std",
"xcm/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"sp-pusd/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"xcm/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-assets/try-runtime",
"pallet-balances/try-runtime",
"sp-pusd/try-runtime",
"sp-runtime/try-runtime",
]
Loading