Mint
mint_stable revalues the vault, checks both floors on the post-mint state, then CPIs into Token-2022 to emit units. The vault PDA is the mint authority — no external key can inflate supply.
Issuance is the act of bringing collateral to the vault and emitting a calibrated stablecoin against it. The path is deliberately short: admit collateral, prove the ratio, mint, and let redemption run the exact same math in reverse. Every unit in circulation is backed by a recorded deposit, and every deposit is priced through the oracle mesh before a single unit is emitted.
Seven instructions carry a stablecoin from registration to redemption. The order is enforced on-chain — you cannot mint before collateral is deposited, and you cannot redeem collateral you have not first unlocked by burning supply.
| Step | Instruction | Effect |
|---|---|---|
| 1 | initialize_config | Admin sets global thresholds and admin key |
| 2 | register_stable | Registers a mint under a peg currency and mode |
| 3 | deposit_collateral | Moves collateral into the vault ATA |
| 4 | mint_stable | Emits units after ratio and breaker checks |
| 5 | burn_stable | Retires supply, unlocks redemption |
| 6 | redeem_collateral | Returns proportional collateral to the issuer |
| 7 | commit_attestation | Attestor writes a signed reserve snapshot |
A stablecoin is registered under exactly one collateral mode, fixed at register_stable time. The mode sets the minimum mint ratio the program will accept. The public demo registers only in the crypto over-collateralized mode — Pegd holds no fiat and makes no real-dollar backing claim.
| Mode | min_ratio_bps | Reserve basis |
|---|---|---|
| OVERCOLLATERALIZED_CRYPTO | 15000 | On-chain crypto, 150% floor (demo mode) |
| ATTESTED_FIAT | 10100 | Off-chain fiat proven by signed attestation |
| RWA_BACKED | 10500 | Tokenized T-bills or notes with attestation |
The two attested modes exist in the type system and the registration path, but they require a custody attestor role and are not exercised by the public demo. Only the crypto mode mints in a fully on-chain, self-verifiable way.
The ratio is the single number the whole framework calibrates against. It is stored as basis points in collateral_ratio_bps — a u32, wide enough that a heavily over-collateralized vault never overflows. A ratio of 10000 is exactly one-to-one; 15000 is 150 percent.
// Ratio in basis points. Peg currency valuation via the oracle.
// collateral_value and minted_value are both e6 fixed-point USD.
fn ratio_bps(collateral_value_e6: u128, minted_value_e6: u128) -> u32 {
if minted_value_e6 == 0 {
return u32::MAX; // nothing minted yet: unbounded coverage
}
((collateral_value_e6 * 10_000) / minted_value_e6) as u32
}
// A mint is only accepted if the POST-mint ratio still clears the floor.
fn assert_mint_allowed(v: &VaultState, cfg: &Config, add_value_e6: u128) -> Result<()> {
require!(!v.is_paused, PegdError::IssuancePaused);
let post = ratio_bps(v.collateral_value_e6, v.minted_value_e6 + add_value_e6);
require!(post >= cfg.circuit_bps, PegdError::CircuitBreaker); // 12000
require!(post >= cfg.min_ratio_bps, PegdError::BelowMinRatio); // 15000 crypto
Ok(())
}Two floors guard every mint. The circuit-breaker floor (circuit_bps, 12000 / 120 percent) is checked first — below it, issuance halts entirely. The mode floor (min_ratio_bps, 15000 / 150 percent for crypto) is the healthy operating minimum a new mint must clear. The ratio is recomputed on-chain from live vault balances on every mint; a client-side number is never trusted.
mint_stable revalues the vault, checks both floors on the post-mint state, then CPIs into Token-2022 to emit units. The vault PDA is the mint authority — no external key can inflate supply.
burn_stable retires units and decrements total_minted. Burning raises the ratio, so it is always permitted — even while issuance is paused — and it is what unlocks proportional redemption.
Redemption is strictly proportional. Burning x percent of outstanding supply releases at most x percent of the vault's collateral, so no redeemer can drain reserves ahead of the peg. The program computes the release amount from raw balances at the moment of the call, never from a cached figure.
Every Pegd stablecoin is a Token-2022 mint with the interest-bearing extension attached at allocation. The extension does not move tokens — it declares a rate, and wallets and explorers compute the accrued amount from it. The rate may be zero; when it is set, the vault PDA is the sole rate authority, updated through a single CPI.
// set_yield_rate: only the vault PDA may change the accrual rate.
// rate is in basis points per year; interest is non-custodial display accrual.
pub fn set_yield_rate(ctx: Context<SetYieldRate>, new_rate_bps: i16) -> Result<()> {
require_keys_eq!(
ctx.accounts.authority.key(),
ctx.accounts.config.admin,
PegdError::Unauthorized
);
anchor_spl::token_2022_extensions::interest_bearing_mint_update_rate(
ctx.accounts.into_update_rate_ctx().with_signer(&[vault_seeds]),
new_rate_bps,
)?;
Ok(())
}Because the yield is expressed through the mint extension rather than a rebasing balance, it never touches the collateral ratio math above — issuance accounting stays denominated in raw minted units, and the interest figure is a presentation layer on top.
Issuance state lives in a small set of PDAs derived from the stablecoin mint. The collateral itself sits in an associated token account owned by the vault PDA, so custody is program-controlled from the first deposit.
config = pda([b"config"], program_id); // global thresholds
stable = pda([b"stable", authority.as_ref()], program_id);
vault = pda([b"vault", stable_mint.as_ref()], program_id);
risk = pda([b"risk", stable_mint.as_ref()], program_id);
// Collateral custody: an ATA owned by the vault PDA.
collateral_vault = associated_token_address(
/* owner */ vault,
/* mint */ collateral_mint,
);