Stablecoin Protocol Security: Invariants, Cascades, and Peg Mechanisms
For a stablecoin, stability is an emergent and fragile state, not an inherent property. Distinct from other DeFi tokens, a stablecoin’s sole mission is peg stability. Every architectural decision—how collateral is chosen, how liquidations are triggered, how the protocol is governed—is ultimately a decision about how the protocol will behave under adversarial pressure. When the pressure comes from market stress, coordinated attack, or oracle failure, these decisions become the difference between a functioning monetary instrument and a catastrophic collapse.
Design choices result in risk specialization rather than complete risk elimination. Stablecoins typically manage certain key risks effectively—such as mitigating collateral volatility with fiat reserves—while implicitly concentrating others, such as custodial and counterparty risks. The goal of this article is to make those concentrations explicit, show you exactly where they live in the code, and arm you with a systematic audit framework.
1. Collateral Ratio Invariants and Their Violation Conditions
Every overcollateralized stablecoin protocol is built on a single core invariant: the value of collateral must always exceed the value of issued debt by a protocol-defined minimum ratio. Violating this invariant means the protocol is insolvent—there is more stablecoin in circulation than the collateral can redeem.
A decentralized, cryptocurrency-collateralized design like MakerDAO’s DAI generates tokens when an investor deposits collateral—typically Ether—into a collateralized debt position (CDP). Based on the value of collateral, an investor can issue (borrow) a certain amount of DAI tokens, with the number limited by a smart contract. This approach is capital inefficient since positions are overcollateralized.
The core invariant can be expressed as:
collateralValue(position) / debtValue(position) >= minimumCollateralRatio
Where minimumCollateralRatio is typically 150% on protocols like MakerDAO (i.e., $150 of ETH for every $100 of DAI minted). This buffer exists to absorb price volatility before positions become undercollateralized.
Invariant Violation Conditions
The invariant can be violated in several distinct ways:
- Collateral price drop: The collateral asset’s market price falls faster than the liquidation mechanism can respond.
- Oracle lag or manipulation: The price reported to the contract diverges from the actual market price, either through a stale feed or deliberate attack.
- Governance changes: A malicious or mistaken parameter change (e.g., raising the debt ceiling or lowering the minimum ratio) allows more stablecoin to be minted against existing collateral.
- Validation bypass: As seen in the Cashio exploit, the attacker exploited a vulnerability where the code failed to verify that the banking token and the minted token matched, allowing the use of worthless tokens to mint real CASH tokens—depositing valueless collateral to drain value from the protocol.
Solidity: Collateral Ratio Calculation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/utils/math/Math.sol";
interface IOracle {
/// @notice Returns price with 18 decimal precision
function latestPrice() external view returns (uint256 price, uint256 updatedAt);
}
contract CollateralVault {
using Math for uint256;
// ─── Constants ───────────────────────────────────────────────────────────
uint256 public constant PRECISION = 1e18;
uint256 public constant MIN_COLLATERAL_RATIO = 150e16; // 150% (1.5e18)
uint256 public constant LIQUIDATION_RATIO = 130e16; // 130% — liquidation threshold
uint256 public constant ORACLE_STALENESS_THRESHOLD = 3600; // 1 hour max age
// ─── State ───────────────────────────────────────────────────────────────
IOracle public immutable oracle;
struct Position {
uint256 collateralAmount; // Raw token units
uint256 debtAmount; // Stablecoin units (18 decimals)
}
mapping(address => Position) public positions;
// ─── Errors ──────────────────────────────────────────────────────────────
error StaleOraclePrice(uint256 updatedAt, uint256 currentTime);
error InsufficientCollateral(uint256 ratio, uint256 minimum);
error PositionAlreadyHealthy(address owner, uint256 ratio);
constructor(address _oracle) {
oracle = IOracle(_oracle);
}
// ─── Core Ratio Logic ────────────────────────────────────────────────────
/// @notice Returns the collateral ratio of a position, scaled to 1e18.
/// A value of 1.5e18 represents 150%.
function getCollateralRatio(address owner) public view returns (uint256 ratio) {
Position storage pos = positions[owner];
if (pos.debtAmount == 0) return type(uint256).max; // No debt → infinite ratio
uint256 collateralValue = _getCollateralValueUSD(pos.collateralAmount);
// ratio = (collateralValue * PRECISION) / debtAmount
ratio = collateralValue.mulDiv(PRECISION, pos.debtAmount);
}
/// @notice Checks whether a position is healthy (above MIN_COLLATERAL_RATIO).
function isHealthy(address owner) public view returns (bool) {
return getCollateralRatio(owner) >= MIN_COLLATERAL_RATIO;
}
/// @notice Checks whether a position is eligible for liquidation.
function isLiquidatable(address owner) public view returns (bool) {
return getCollateralRatio(owner) < LIQUIDATION_RATIO;
}
// ─── Minting ─────────────────────────────────────────────────────────────
/// @notice Deposit collateral and mint stablecoins against it.
function depositAndMint(uint256 collateralAmount, uint256 mintAmount)
external
{
// Optimistic state update first (CEI pattern)
Position storage pos = positions[msg.sender];
pos.collateralAmount += collateralAmount;
pos.debtAmount += mintAmount;
// Validate the new ratio AFTER update — prevents over-minting
uint256 ratio = getCollateralRatio(msg.sender);
if (ratio < MIN_COLLATERAL_RATIO) {
revert InsufficientCollateral(ratio, MIN_COLLATERAL_RATIO);
}
// Transfer collateral in; mint stablecoin out
// (token transfer logic omitted for brevity)
}
// ─── Oracle Helpers ──────────────────────────────────────────────────────
/// @dev Returns USD value of `amount` units of collateral.
/// Reverts on stale price to prevent invariant violations.
function _getCollateralValueUSD(uint256 amount)
internal
view
returns (uint256 value)
{
(uint256 price, uint256 updatedAt) = oracle.latestPrice();
// CRITICAL: Always enforce oracle freshness.
// A stale oracle is a silent invariant violation waiting to happen.
if (block.timestamp - updatedAt > ORACLE_STALENESS_THRESHOLD) {
revert StaleOraclePrice(updatedAt, block.timestamp);
}
// value = (amount * price) / PRECISION
value = amount.mulDiv(price, PRECISION);
}
}
2. Liquidation Cascade Risk
Liquidation is the self-correction mechanism of a collateral-backed stablecoin. When a position’s collateral ratio drops below the liquidation threshold, liquidators pay off some or all of the position’s debt in exchange for the collateral—at a discount. This discount is the liquidation bonus, and it is the economic incentive that makes the system function.
The mechanics of a liquidation cascade rely on the automated interactions between smart contracts, market prices, and network participants known as liquidators. Every open position in a decentralized lending protocol has a health factor—a mathematical value representing the safety of the loan based on the current collateral value compared to the borrowed amount.
The cascade begins when a price drop triggers an initial set of liquidations. Those liquidations dump collateral onto the market, pushing the price further down. This subsequent price drop lowers the collateral value for other borrowers who were previously operating within safe LTV limits, causing their positions to become undercollateralized and triggering another round of automated sell-offs. The cycle repeats continuously, creating a severe downward spiral in asset prices that can rapidly drain liquidity from decentralized exchanges and cause massive price dislocations across the broader DeFi market.
Black Thursday: A Cascade Case Study
One of the earliest and most widely studied cascade events occurred in March 2020 during Black Thursday. A sudden collapse in global financial markets caused the price of Ethereum to drop by more than 50% in a single day. The rapid price decline triggered a massive wave of liquidations on the MakerDAO protocol. High network congestion severely delayed oracle price updates and prevented users from depositing additional collateral to save their positions. Furthermore, the congestion prevented liquidator bots from operating effectively, allowing some participants to win liquidation auctions for zero cost—resulting in a severe accumulation of bad debt for the protocol.
This event identified three distinct failure modes that must be addressed in any liquidation system:
- Oracle latency under congestion
- Liquidator bot incapacitation
- Auction mechanics that can be exploited by zero-bid attacks
Solidity: Liquidation Logic with Cascade Guard
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
contract LiquidationEngine is ReentrancyGuard {
using Math for uint256;
// ─── Constants ───────────────────────────────────────────────────────────
uint256 public constant LIQUIDATION_BONUS = 5e16; // 5% bonus to liquidators
uint256 public constant LIQUIDATION_RATIO = 130e16; // Trigger at 130% CR
uint256 public constant MAX_LIQUIDATION_PCT = 50e16; // Max 50% per call (cascade guard)
uint256 public constant PRECISION = 1e18;
// ─── Errors ──────────────────────────────────────────────────────────────
error PositionHealthy(address owner, uint256 ratio);
error ExcessiveLiquidation(uint256 requested, uint256 maxAllowed);
error InsufficientLiquidatorFunds();
// ─── Events ──────────────────────────────────────────────────────────────
event PositionLiquidated(
address indexed owner,
address indexed liquidator,
uint256 debtRepaid,
uint256 collateralSeized,
uint256 bonus,
uint256 resultingRatio
);
// (Assume CollateralVault is composed or inherited)
CollateralVault public immutable vault;
constructor(address _vault) {
vault = CollateralVault(_vault);
}
// ─── Liquidation Entry Point ──────────────────────────────────────────────
/// @notice Liquidate an undercollateralized position.
/// @param owner The address of the position to liquidate.
/// @param debtToPay The amount of stablecoin debt the liquidator repays.
///
/// @dev MAX_LIQUIDATION_PCT caps partial liquidations to prevent a single
/// liquidator from dumping the entire collateral position in one call,
/// which would amplify the downward price pressure causing the cascade.
function liquidate(address owner, uint256 debtToPay)
external
nonReentrant
{
// ── 1. Pre-condition checks ──────────────────────────────────────────
uint256 currentRatio = vault.getCollateralRatio(owner);
if (currentRatio >= LIQUIDATION_RATIO) {
revert PositionHealthy(owner, currentRatio);
}
CollateralVault.Position memory pos = _getPosition(owner);
// ── 2. Cascade Guard: cap debt repayment at MAX_LIQUIDATION_PCT ──────
uint256 maxDebt = pos.debtAmount.mulDiv(MAX_LIQUIDATION_PCT, PRECISION);
if (debtToPay > maxDebt) {
revert ExcessiveLiquidation(debtToPay, maxDebt);
}
// ── 3. Calculate collateral to seize (debt repaid + bonus) ───────────
// collateralSeized = debtToPay * (1 + LIQUIDATION_BONUS) / collateralPrice
uint256 collateralPrice = _getOraclePrice();
uint256 debtWithBonus = debtToPay.mulDiv(
PRECISION + LIQUIDATION_BONUS, PRECISION
);
uint256 collateralSeized = debtWithBonus.mulDiv(PRECISION, collateralPrice);
// Clamp to available collateral (safety: never over-seize)
collateralSeized = Math.min(collateralSeized, pos.collateralAmount);
// ── 4. State updates (Checks-Effects-Interactions) ───────────────────
_reduceDebt(owner, debtToPay);
_reduceCollateral(owner, collateralSeized);
// ── 5. Transfer assets ───────────────────────────────────────────────
// Pull stablecoin from liquidator; push collateral to liquidator
_pullStablecoin(msg.sender, debtToPay);
_pushCollateral(msg.sender, collateralSeized);
// ── 6. Emit event with resulting ratio for off-chain monitoring ───────
uint256 resultingRatio = vault.getCollateralRatio(owner);
emit PositionLiquidated(
owner,
msg.sender,
debtToPay,
collateralSeized,
collateralSeized - debtToPay.mulDiv(PRECISION, collateralPrice),
resultingRatio
);
}
// ── Internal helpers (stubs) ─────────────────────────────────────────────
function _getPosition(address owner)
internal view returns (CollateralVault.Position memory pos)
{
(uint256 col, uint256 debt) = vault.positions(owner);
pos.collateralAmount = col;
pos.debtAmount = debt;
}
function _getOraclePrice() internal view returns (uint256 price) {
(price, ) = vault.oracle().latestPrice();
}
function _reduceDebt(address owner, uint256 amount) internal { /* ... */ }
function _reduceCollateral(address owner, uint256 amount) internal { /* ... */ }
function _pullStablecoin(address from, uint256 amount) internal { /* ... */ }
function _pushCollateral(address to, uint256 amount) internal { /* ... */ }
}
The Deleveraging Spiral
This deleveraging process can lead to cascades of fire sales as the initial collateral sale marks down the collateral value of other levered traders and leads to further liquidations—a crypto liquidation downward spiral. Undervalued collateral feeds forced liquidations of solvent positions, which feed cascading sell-offs and market panic. Circuit breakers can interrupt this feedback loop: halting minting or adjusting collateral ratios in extreme volatility helps prevent an insolvency spiral.
3. Algorithmic Stablecoin Death Spiral Mechanics
Algorithmic stablecoins represent the highest-risk design in the stablecoin design space. This experimental class of stablecoins attempts to maintain its peg through algorithms and market incentives, rather than full reserve backing. Algorithmic stablecoins introduce the most complex risks. Their stability relies on market confidence in algorithmic mechanisms. Loss of confidence can trigger reflexive selling, overwhelming stabilizers and causing collapse, as demonstrated by the UST incident.
The Terra/Luna Death Spiral
The collapse of TerraUSD (UST) in May 2022 demonstrated how algorithmic stablecoins can lose their peg during market stress, wiping out over $60 billion in value and triggering broader market contagion. The incident highlighted the risks of experimental tokenomics and insufficient collateralization mechanisms.
The mechanism of the death spiral operated through a reflexive feedback loop:
When large holders began moving capital out of UST and Anchor, triggering heavy selling pressure on the stablecoin, and UST slipped below its one-dollar target, the arbitrage mechanism kicked in—UST holders rushed to redeem their coins for Luna, rapidly expanding Luna’s circulating supply. Each wave of redemptions minted more Luna, driving down its price and undermining the very collateral that was supposed to support UST.
The sharp drop in LUNA’s market capitalization—which served as the assets backing the liabilities represented by the circulating UST—led to a significant loss of market confidence. As users perceived that the value of the backing assets was rapidly declining relative to the outstanding obligations, they responded by massively selling their holdings, exacerbating the depeg and fueling the self-reinforcing downward spiral typical of a bank run.
Iron Finance: The Precursor
Terra was not the first. The failure of the Terra project represents additional proof of the intrinsic fragility of algorithmic stablecoins that became already evident after the first large-scale crypto “bank run” suffered by Iron Finance in June 2021. Iron Finance was also a two-coin system based on an algorithmic stablecoin (IRON) and a token counterpart (TITAN), which collapsed after a cascade selloff of TITAN due to significant selling pressure by some “whales.” The strategy used to bring down Iron Finance was very similar to the one observable in the LUNA-UST case.
The Structural Fragility
UST’s dual-token system lacked collateral, relying on market confidence and unsustainable 20% APYs via Anchor Protocol, triggering a death spiral. The death spiral has three structural prerequisites:
- Reflexive collateral: The asset backing the stablecoin is the protocol’s own governance/seigniorage token—whose value is derived from confidence in the stablecoin.
- Unconstrained mint/burn: The protocol allows unlimited minting of the volatile token when the stablecoin is redeemed, with no supply cap or circuit breaker.
- Concentration of demand: A single yield source (like Anchor’s 20% APY) artificially concentrates demand, such that its withdrawal triggers a mass exodus.
Automated emergency circuit breakers—on-chain mechanisms to halt minting or force redemption when set thresholds are breached—aim to avoid the kind of death spiral that Terra triggered in 2022.
4. Oracle Dependency and Peg Stability
Decentralized stablecoins rely heavily on oracles and liquidation mechanisms to maintain their pegs, creating additional attack surfaces where price manipulation or oracle failures can destabilize the entire stablecoin ecosystem.
Peg maintenance is the process of ensuring that the market value of the stablecoin remains aligned with its intended fiat equivalent, and this process is dependent on the integrity of the underlying oracle infrastructure.
The Oracle Attack Surface
Oracle manipulation accounted for over $400 million in DeFi losses during 2024-2025. Price oracle manipulation exploits represent 34.3% of exploits in real-world datasets, identifying it as the most common exploit among machine-unauditable bugs—a category of vulnerabilities that, as of 2022, remain undetectable by existing automated tools.
Oracle attacks take two primary forms:
Artificial overvaluation: Artificial overvaluation allows excess stablecoin issuance beyond real backing, weakening the peg.
Artificial undervaluation: Artificial undervaluation triggers mass liquidations of otherwise healthy vaults, causing collateral fire sales and market contagion.
TWAP Manipulation
Spot-price oracles (reading the current pool price directly) are trivially manipulable via flash loans in a single block. Time-Weighted Average Prices (TWAPs) were designed to resist this, but they carry their own vulnerabilities: TWAPs were designed to resist single-block manipulation. Multi-block attacks bypass this by controlling multiple blocks through MEV techniques.
Academic and central-bank research has repeatedly highlighted that both spot and TWAP oracles can be manipulated if liquidity is thin or windows are too short.
The Staleness Problem
Chainlink multisigs can immediately block access to price feeds at will, so just because a price feed is working today does not mean it will continue to do so indefinitely. Smart contracts should handle this by wrapping calls to oracles in try/catch blocks and dealing appropriately with any errors. If a configured oracle feed has malfunctioned or ceased operating, but the smart contract does not have any alternative data source, nor does the contract allow updates to data sources, that contract will be permanently bricked—which is especially damaging for stablecoin protocols where large amounts of user value are stored as collateral that can no longer be withdrawn.
Defense: Multi-Source Oracle Pattern
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title SecureOracleAggregator
/// @notice Aggregates prices from Chainlink and a Uniswap V3 TWAP.
/// Falls back to either source individually if one is unavailable.
/// Reverts if deviation between sources exceeds MAX_DEVIATION.
contract SecureOracleAggregator {
// ─── Config ──────────────────────────────────────────────────────────────
uint256 public constant MAX_DEVIATION = 5e16; // 5% max spread between sources
uint256 public constant STALENESS_THRESHOLD = 3600; // 1-hour Chainlink freshness
uint256 public constant TWAP_INTERVAL = 1800; // 30-min Uniswap V3 TWAP window
uint256 public constant PRECISION = 1e18;
address public immutable chainlinkFeed; // AggregatorV3Interface
address public immutable uniswapPool; // IUniswapV3Pool
// ─── Errors ──────────────────────────────────────────────────────────────
error OraclePriceDeviation(uint256 chainlinkPrice, uint256 twapPrice, uint256 deviation);
error AllOraclesStale();
error ZeroPrice();
// ─── Price Retrieval ─────────────────────────────────────────────────────
/// @notice Returns a manipulation-resistant price using multiple sources.
/// Uses the median of available, fresh sources.
function getPrice() external view returns (uint256 price) {
(bool clOk, uint256 clPrice) = _tryChainlink();
(bool twapOk, uint256 twapPrice) = _tryTWAP();
if (!clOk && !twapOk) revert AllOraclesStale();
if (clOk && twapOk) {
// Both available: validate deviation, return average
uint256 deviation = _absoluteDifference(clPrice, twapPrice)
.mulDiv(PRECISION, clPrice);
// SECURITY: If sources diverge by > MAX_DEVIATION, halt.
// This prevents an attacker who compromised one source from
// silently creating a manipulated price.
if (deviation > MAX_DEVIATION) {
revert OraclePriceDeviation(clPrice, twapPrice, deviation);
}
price = (clPrice + twapPrice) / 2;
} else if (clOk) {
price = clPrice; // Fallback: Chainlink only
} else {
price = twapPrice; // Fallback: TWAP only
}
if (price == 0) revert ZeroPrice();
}
// ─── Source Wrappers ─────────────────────────────────────────────────────
function _tryChainlink() internal view returns (bool ok, uint256 price) {
try IAggregatorV3(chainlinkFeed).latestRoundData() returns (
uint80, int256 answer, uint256, uint256 updatedAt, uint80
) {
if (answer <= 0) return (false, 0);
if (block.timestamp - updatedAt > STALENESS_THRESHOLD) return (false, 0);
price = uint256(answer) * 1e10; // Normalize 8-decimal Chainlink to 18
ok = true;
} catch {
return (false, 0);
}
}
function _tryTWAP() internal view returns (bool ok, uint256 price) {
try IUniswapV3Pool(uniswapPool).observe(
_buildSecondsAgo(TWAP_INTERVAL)
) returns (int56[] memory tickCumulatives, uint160[] memory) {
int56 tickDiff = tickCumulatives[1] - tickCumulatives[0];
int24 avgTick = int24(tickDiff / int56(uint56(TWAP_INTERVAL)));
price = _tickToPrice(avgTick);
ok = (price > 0);
} catch {
return (false, 0);
}
}
function _absoluteDifference(uint256 a, uint256 b)
internal pure returns (uint256)
{
return a > b ? a - b : b - a;
}
function _buildSecondsAgo(uint256 interval)
internal pure returns (uint32[] memory arr)
{
arr = new uint32[](2);
arr[0] = uint32(interval);
arr[1] = 0;
}
function _tickToPrice(int24 tick) internal pure returns (uint256) {
// 1.0001^tick, approximated — use TickMath.getSqrtRatioAtTick in production
return 0; // stub
}
}
interface IAggregatorV3 {
function latestRoundData() external view returns (
uint80 roundId, int256 answer, uint256 startedAt,
uint256 updatedAt, uint80 answeredInRound
);
}
interface IUniswapV3Pool {
function observe(uint32[] calldata secondsAgos)
external view returns (int56[] memory, uint160[] memory);
}
Median-of-three pricing using Chainlink, TWAP, and a secondary feed like Pyth or Band provides excellent manipulation resistance, because the attacker would need to compromise two of three independent systems simultaneously.
5. The Stablecoin-as-Collateral Problem
One of the most structurally dangerous configurations in DeFi is accepting the protocol’s own stablecoin—or a closely correlated stablecoin—as collateral for minting more of the same stablecoin. This creates a recursive debt structure where the value of the collateral is endogenously dependent on the stability of the asset it is supposed to secure.
The widespread use of stablecoins as debt-financed collateral increases financial stability risks in the DeFi ecosystem. A crypto-asset can be used as collateral in a DeFi loan protocol to help mint other crypto-assets such as stablecoins, which in turn can be further locked into a decentralized “money market” and further tokenized.
This looping creates an illusion of overcollateralization. Consider this scenario:
User mints 1,000 STABLE using $1,500 ETH (150% CR) ──► Healthy
User deposits 1,000 STABLE as collateral in PROTOCOL_B
PROTOCOL_B mints 666 STABLE_B against 1,000 STABLE (150% CR) ──► Healthy
On paper, each protocol is fully collateralized. In practice, both legs of the position depend on the market price of the underlying collateral. If STABLE depegs by 10%, both positions simultaneously become undercollateralized.
The Correlation Collapse
Diversification improves resilience, but introduces correlation risks: if many collateral assets depend on USD-pegged stablecoins, stress in USDC/USDT cascades into DAI. Collateral choices encode hidden dependencies on CeFi actors and other protocols, weakening the “pure DeFi” narrative.
Protocols must implement the following guards against recursive collateral structures:
// ─── Collateral Whitelist with Reflexivity Guard ──────────────────────
```solidity
mapping(address => bool) public approvedCollateral;
mapping(address => bool) public isSyntheticAsset; // tracks protocol's own minted tokens
function addCollateral(address token) external onlyGovernance {
// Prevent the stablecoin itself or any synthetic from being used as collateral
require(!isSyntheticAsset[token], "reflexive collateral prohibited");
require(token != address(this), "cannot self-collateralize");
approvedCollateral[token] = true;
}
Stablecoin Security Audit Checklist
Peg mechanism
- The redemption path (stablecoin → collateral at $1) is always available and not subject to rate limiting that could break the peg
- Arbitrage paths that restore the peg are permissionless and do not require protocol admin action
- The peg mechanism is stress-tested against oracle failure, collateral price crash, and liquidity crises
Collateral quality
- All accepted collateral is on an explicit allowlist with governance-controlled additions
- Reflexive collateral (the stablecoin itself or protocol tokens) is prohibited
- Collateral concentration limits prevent single-asset systemic risk
- Collateral oracle is multi-source, TWAP-protected, and staleness-guarded
Liquidation system
- Liquidation thresholds ensure undercollateralized positions are cleared before bad debt accrues
- Liquidation bonus is large enough to incentivize liquidators at peak gas on the target network
- Dutch auction or equivalent mechanism prevents toxic liquidation spirals
- Bad debt socialization has an explicit, documented trigger and cap
Algorithmic mechanisms
- The death spiral scenario (price drops → redemptions → more drops) has been modeled
- Protocol-owned liquidity or reserve funds provide a floor
- Minting and burning are rate-limited during extreme volatility to prevent bank runs
Smart contract risks
- All oracles are validated for staleness, zero price, and decimal consistency
- Minting functions cannot be triggered by anyone except authorized paths
- Emergency pause covers all minting paths without blocking redemptions