Development of collateralized stablecoin
Protocol attracted $40M TVL in three months. Fourth month ETH fell 35% in 4 hours — faster than liquidation bot processed queue. Several positions with 150% collateral ratio became undercollateralized before liquidation. Protocol minted unsecured stablecoins. This is how systemic risk works in overcollateralized stablecoin — not through contract hack, but through architectural mistake in liquidation mechanics.
Collateral architecture: where real problems hide
Liquidation mechanics and "oracle lag" problem
Hardest part of collateralized stablecoin — not mint/burn itself, but liquidation system under load. Classic scheme: if collateralRatio < liquidationThreshold, position can be liquidated. Problem starts when Chainlink price feed updates on heartbeat (usually 1 hour or on >0.5% move), but asset price falls faster.
On flash crash ETH -20% in 30 minutes several things happen simultaneously:
- on-chain price from Chainlink not updated yet (last update 25 minutes ago)
- real price already 18% below oracle price
- liquidation bots see positions as "healthy" by on-chain data
- when oracle updates liquidation queue becomes huge
- gas wars between bots → liquidators pay 200-500 gwei → some positions just don't make it
Solution — two-layer check: main Chainlink feed + Uniswap V3 TWAP as sanity check. If gap exceeds 5%, protocol enters "emergency mode" with restrictions on new mint. This is what MakerDAO realized through OSM (Oracle Security Module) with 1 hour delay — not perfect solution but gives time for governance reaction.
Bad debt and coverage mechanism
In Liquity v1 on liquidation debt covered from Stability Pool. If pool empty, debt distributed among all vault holders through "redistribution". Elegant, but creates hidden risk: under mass liquidations redistribution dilutes collateral ratio of healthy positions, potentially triggering cascade.
In our implementation we use insurance reserve (Insurance Fund), formed from liquidation penalty share (usually 10-13%). Under normal operation accumulates. On bad debt event — covers first losses before risk transfers to governance token holders.
Price manipulation through flash loan
Classic vector: take flash loan on large sum, deposit as collateral, mint stablecoin at inflated price (if oracle uses spot price from DEX pool), withdraw stablecoin. TWAP (Time-Weighted Average Price) closes this — spot price manipulation affects TWAP only with sustained holding, making attack expensive.
For new tokens with low liquidity TWAP also unreliable. That's why whitelist collateral assets with minimum liquidity threshold ($50M+) — not protocol limitation, but safety mechanism.
How we build overcollateralized stablecoin
Contract architecture
Separate system into independent modules:
| Module | Responsibility | Upgradeability |
|---|---|---|
VaultManager |
Open/close positions, collateral accounting | UUPS |
PriceOracle |
Chainlink + TWAP aggregation, circuit breaker | Replaceable |
LiquidationEngine |
Liquidation queue, dutch auction | UUPS |
StabilityPool |
Buffer for liquidation coverage | Immutable |
StablecoinToken |
ERC-20 with mint/burn only from VaultManager | Immutable |
StablecoinToken — immutable intentionally. Stablecoin holders shouldn't depend on governance voting to change token logic.
Dutch auction for liquidations
Instead of fixed liquidation penalty use dutch auction: liquidation discount starts at 0% and increases every N blocks until someone takes position. Solves two problems:
- Competition between liquidation bots switches from gas wars to "who accepts favorable price first"
- Protocol doesn't overpay liquidators under normal conditions
Liquity v2 and Gravita use similar approach. We add limit: if auction lasts longer than maxAuctionDuration blocks without buyer — position moves to redistribution to avoid stuck bad debt.
System parameters and governance
Key parameters governance should control:
-
minimumCollateralRatio— usually 110-150% depending on asset volatility -
liquidationPenalty— 5-15%, must be sufficient to motivate bots -
borrowingFee— one-time fee on mint, regulates demand -
stabilityFee(optional) — continuous rate, like interest rate in MakerDAO
For new protocols we recommend starting with conservative parameters (MCR 150%, penalty 10%) and lowering as on-chain history accumulates.
Testing: fork-tests on crash scenarios
No unit-test replaces fork-test on real historical data. Test protocol on several scenarios:
Black Thursday 2020 (ETH -55% in 24h): check liquidation queue processes correctly with zero Stability Pool liquidity.
LUNA/UST depeg 2022: simulate rapid collateral asset fall with simultaneous sell pressure on stablecoin itself. Check oracle circuit breaker.
Gas spike to 3000 gwei: check liquidations economically viable even at extreme gas. If not — position sizes or penalty need revision.
Foundry vm.createFork + vm.rollFork allows reproducing exact mainnet state at any historical moment. This is standard for our CDP protocol testing.
Development process
Analytics (3-5 days). Define whitelisted assets, system parameters, liquidation mechanics. Analyze competitors: Liquity, Gravita, Raft, Prisma.
Design (5-7 days). Storage layout, module interfaces, event schema for The Graph indexing.
Development (4-8 weeks). Contracts + comprehensive tests: unit, integration, fork-tests on historical scenarios, fuzz-tests through Echidna with property-based system invariant checks.
External audit (mandatory). For CDP protocols with >$1M TVL potential — minimum one external audit from specialized company (Trail of Bits, Sherlock, Code4rena contest). Budget and time in roadmap upfront.
Deployment. Multisig through Gnosis Safe on all admin functions. Timelock on key parameter changes (minimum 24-48 hours).
Timeline estimates
Minimal implementation (one collateral type, basic liquidation) — 6-8 weeks development. Full protocol with multiple collateral types, Dutch auction liquidations, Stability Pool and governance — 2-4 months including audit. Timeline depends significantly on parameterization complexity and test coverage requirements.
Cost calculated individually after requirements analysis.







