The idea behind ministable was to build the smallest stablecoin possible: the engine and the currency live in the same contract. The implementation has grown since the first version, but the core ideas still hold, and a lot of interesting things happen onchain.

What is Ministable?

At its core, a ministable is a collateralized debt position (CDP). The collateral can be almost anything: the chain's native cryptocurrency like ETH, an ERC-20 token, or even another stablecoin. As long as there's a reliable price oracle for it, you can create a stablecoin for whatever you need. Right now every deployment is permissioned (only the factory owner can deploy a new ministable), but I plan to open that up once the protocol has been live for a few years.

The first deployment, currently on testnet, is mUSD (Ministable USD): a CDP backed by ETH and pegged to the US dollar.

Dissecting the CDP engine

The cdp.vy Vyper module is the core engine of the protocol. Combined with the erc20 module, it forms a ministable, which is how the engine and the token end up in one contract. It holds all of the stablecoin's accounting: positions, debt, the stability fee, liquidations, bad debt, redemptions, the surplus, and the oracle.

One design choice is worth knowing up front: cdp.vy never moves collateral. Its functions update the books and return how much collateral should be paid out. The module wrapping it (cdp_native for ETH, cdp_erc20 for tokens) sends and receives the actual funds, and only after the accounting is done.

Collateral ratio

First is the minimum collateral ratio, a constant set to 150%. For every $1 of mUSD, at least $1.50 worth of ETH has to back the position.

Liquidation bonus

When a position falls below 150%, anyone can liquidate it. The liquidator repays part of the debt and receives 110% of that amount in collateral, a 10% bonus. They only repay enough to bring the position back to 150%, and the borrower keeps the rest of their collateral.

Fees

There are three fees:

  • Redemption fee. Anyone can redeem mUSD for $1 of collateral from any healthy position. The fee starts at 0.5% for a position at 150% and rises by 1% for every 100% of collateral ratio above that, up to a 5% cap at 600%. The fee goes to the borrower being redeemed, not to the protocol. So redeemers go after the riskiest positions first, and safer borrowers get paid more when they are redeemed.
  • Swap fee. A 0.5% spread the protocol keeps when it sells surplus mUSD or pays out reserve collateral to cover bad debt. Without it, callers could profit from trading against a lagging oracle price.
  • Stability fee. Interest charged on all outstanding debt. It's set at deployment, capped at 10% a year, and minted to the protocol's surplus. That surplus is the first line of defense against bad debt.

Oracle

A few immutables configure the oracle: the Chainlink price feed itself, and ORACLE_TIMEOUT, the maximum age of a price. The timeout is set per network to the feed's heartbeat plus a buffer, so stale data gets rejected. On L2s there's also a sequencer uptime feed. If the sequencer goes down, prices aren't trusted again until it has been back up for an hour, so nobody gets liquidated on a price they had no chance to react to.

How the engine works

Debt shares

Debt isn't stored as a plain mUSD amount. Each position holds debt shares, and a global rate_index grows every second by the stability fee. Your debt is your shares times the index. This lets interest accrue on every position at once without the contract touching each one. Whenever the index moves, the new interest is minted as mUSD to the contract itself. That balance is the surplus.

Opening and closing a position

You deposit collateral, then mint mUSD against it. The mint only goes through if your ratio stays at or above 150% afterwards. To unwind, you burn mUSD to repay your debt and withdraw your collateral, and the same 150% check applies to every withdrawal.

Liquidations

Liquidation has three cases, depending on how far underwater the position is:

  1. Collateral worth at least 110% of the debt: the liquidator repays just enough to restore 150% and collects their 10% bonus.
  2. Collateral covers the debt but not the bonus: the liquidator repays everything and takes all the collateral. The bonus shrinks toward zero, but no debt is lost.
  3. Collateral worth less than the debt: the liquidator repays what the collateral covers at 110% and takes all of it. The remaining debt is written off as bad debt.

Surplus, reserve and bad debt

Because interest is minted as mUSD to the contract, borrowers need a way to get that mUSD to repay with. buy_surplus sells it for collateral at the oracle price minus the 0.5% swap fee, and the collateral it brings in goes into the reserve.

Bad debt is absorbed in two layers. First, the surplus is automatically burned against it. Anything left can be cleared by anyone through cover_bad_debt, which burns their mUSD in exchange for collateral from the reserve.

Redemptions

Finally, redemptions put a floor under the peg. If mUSD trades below $1, anyone can buy it cheaply and redeem it for $1 of collateral (minus the fee) from a healthy position. Since the fee is capped at 5%, the floor should never drop below $0.95.

Try it on Base Sepolia

mUSD is live on Base Sepolia, Base's testnet. The contract is deployed at:

0x455211D1b760d9b25A794fb788Ad3ADce36aFc6C

You can inspect it on Base, where you'll find every position opened, every mint and burn, and any liquidations or redemptions as they happen.

Because Base is an L2, this deployment also uses the sequencer uptime check described above. If the Base sequencer goes down, the contract won't trust prices again until it has been back up for an hour.

To try it yourself, grab some Base Sepolia ETH from a faucet, deposit it as collateral, and mint mUSD against it. Keep your ratio above 150%, and you're safe. Let it slip below, and someone can liquidate you. It's testnet ETH, so this is the best place to see that happen firsthand.