DEV Community

Cover image for Ministable: a CDP engine and a stablecoin in one contract
Rafael Abuawad
Rafael Abuawad

Posted on Originally published at x.com

Ministable: a CDP engine and a stablecoin in one contract

"We believe that stable digital assets [...] are essential to realizing the full potential of blockchain technology." (The Maker Protocol whitepaper)

For the last few days, I've been working on a new project called ministable. It started with a simple question: can you fit an entire CDP engine and the stablecoin it issues into a single smart contract? That was the whole premise. It turns out you can.

I'd been reading a lot about stablecoins: how they're designed and what each design trades away. One thing kept bothering me. Years after the Terra/LUNA collapse, no decentralized stablecoin has come close to the scale of USDT or USDC. So I started digging into the designs.

What is a CDP?

A CDP (collateralized debt position) is a loan you take out against your own crypto. You lock collateral in a contract, for example, ETH, and mint stablecoins against it. You always have to lock more value than you borrow. To get your collateral back, you repay the stablecoins you minted plus interest.

If the price of your collateral drops and your position falls below the required ratio, anyone can liquidate it. They repay part of your debt and receive some of your collateral at a discount. That's what keeps every stablecoin in circulation backed by more than a dollar of collateral.

Inspiration: DAI and Microstable

Ministable is inspired by two projects: DAI from MakerDAO and Microstable.

DAI is the original decentralized, crypto-backed stablecoin. It's widely accepted, widely used, and has a lot of unique properties. The first version, Single-Collateral DAI, was backed only by ETH, and that's the version ministable is closest to. Reading the DAI whitepaper, I was struck by how simple and useful the core idea is.

Building a stablecoin isn't easy, though. You can build something that technically holds its peg. The hard part is building something that scales.

DAI is the king of decentralized stablecoins (I'm counting DAI and USDS as one). Plenty of protocols have tried to take its place, and so far they've all failed. But even DAI has a scaling problem. It's huge compared to any other decentralized stablecoin, yet I don't see it overtaking USDC or USDT. Overcollateralization is part of the reason: every dollar of DAI needs more than a dollar of crypto locked behind it, so supply is limited by how much collateral people are willing to lock up.

Still, the design is solid and worth exploring onchain. So I set out to build a stablecoin engine and its token in a single contract, and thanks to Vyper's module system, I could.

Ministable: mUSD

The first ministable deployment is mUSD, a stablecoin pegged to the US dollar and backed by ETH. Like everything else in this project, the design is minimal, and it works like any other CDP-backed stablecoin:

  • Minting. You deposit ETH and mint mUSD against it, as long as your position stays at a 150% minimum collateral ratio. That means at least $150 of ETH for every $100 of mUSD.
  • Liquidations. If your position falls below 150%, anyone can liquidate it. The liquidator repays part of your debt and gets 110% of what they repaid in ETH, which is a 10% bonus. They only repay enough to bring you back to 150%, and you keep the rest of your collateral.
  • Redemptions. Anyone can swap mUSD for $1 of ETH from any healthy position, minus a 0.5% fee that goes to that position's owner. If mUSD trades below $1, buying it and redeeming it is profitable, so redemptions put a floor under the peg.
  • Stability fee. Debt grows over time at a fixed per-second rate, set at deployment and capped at 10% a year. The interest is charged in mUSD and minted into the protocol's surplus.
  • Surplus and bad debt. If a liquidated position's collateral can't cover its debt, the shortfall becomes bad debt, and the surplus is burned to cancel it. Anyone can also buy surplus mUSD with ETH at the oracle price. That ETH goes into a reserve, which can cover any bad debt the surplus can't.

Building this taught me how hard stablecoin design really is. Every mechanism exists to close a gap left by another one.

Minimal code

The engine and the token live in a single contract. The goal from the start was something tiny: simple to audit and simple to reason about. Without comments, the whole system (token, CDP engine, and native-ETH wrapper) is under 300 lines of Vyper, without counting the ERC-20 functions.

Security

The code has not been audited yet, and although I'm looking for money to do an audit, I think that is somewhat far away. It has undergone a few code reviews by other developers, but nothing substantial.

Top comments (4)

Collapse
 
cryptostrapon profile image
cryptostrapon •

One practical point before this gets traction: mUSD is already the ticker of mStable's older stablecoin, and copycat tokens love reused tickers. Pinning the canonical contract address in the README and the token metadata will save someone a bad swap. I'm also curious how the redeemed position gets picked, since letting the redeemer choose any healthy one pushes redemption risk onto the safest borrowers.

Collapse
 
rabuawad profile image
Rafael Abuawad •

Yeah, did a little research, and the ticker is taken, but I think we are going to do just fine. To be fair, no official deployment is live yet, and I'm still changing the code almost daily. I will deploy the latest version to testenet next week

About the redeemed position getting picked right now, the redeemer can choose whomever they like. There is another version with a sorted linked list with interest positions attached, so the positions paying the least amount of interest are the first ones to go; didn't like the implementation that much, but is worth revisiting

Collapse
 
bloqarl profile image
Carlos (Bloqarl) •

Nice project, under 300 lines is really how a first version should look. One thing I'd check before you pay for an audit: is there a minimum debt per position? With a 10% liquidation bonus, a tiny position stops being worth liquidating once gas costs more than the bonus, so those can slide under 100% and end up as bad debt. Liquity has a minimum debt per trove partly for that reason.

Also, which oracle does mUSD read, and does the surplus buy check how old the price is? If the price lags after ETH drops, someone can buy surplus mUSD for less than a dollar of real ETH.

Collapse
 
rabuawad profile image
Rafael Abuawad •

Thank you very much

Yes, so this is a known issue with the protocol: some positions are too small, so the incentives to liquidate them are not worth it. Trying to mitigate it has resulted in a few other issues, but the position would have to be tiny, less than $0.5 in profit

Currently, the system is supposed to work with Chainlink's price feed, which has a decent enough heartbeat, and Chainlink updates it automatically if the movement is significant, but theoretically some should be able to buy mUSD for less than a dollar of real ETH