articleDec 7, 2022
Damn Vulnerable DeFi — Unstoppable (accounting assert DoS)
High-level look at DVDeFi Challenge #1 Unstoppable: flash-loan logic that asserts an internal poolBalance equals the token’s raw balance, so a direct transfer can halt loans. Solve steps omitted.
Damn Vulnerable DeFi Challenge #1 — Unstoppable
Educational wargame by @tinchoabbate. Public contracts live under the unstoppable challenge tree. Solve scripts and PoC omitted.
Theme
UnstoppableLender tracks deposits in an internal poolBalance and offers free flash loans. A helper receiver contract shows the intended borrow/repay pattern. The player starts with a small DVT balance; the pool holds a large one.
Root-cause concept
- Accounting invariant enforced with
assert: before lending, the contract requirespoolBalance == token.balanceOf(address(this)) poolBalanceonly increases through the officialdepositTokenspath- ERC-20 tokens can usually be transferred directly to the lender, increasing the raw balance without updating
poolBalance - Once those diverge, the assert fails and flash loans stop (availability failure / DoS of the feature)
Impact (abstract)
In the lab, a tiny gratuitous transfer can permanently disable the pool’s flash-loan API. In production terms: brittle equality checks between internal ledgers and raw token balances are a classic griefing footgun.
Mitigations / lessons
- Prefer soft checks or accounting that tolerates unexpected donations; or explicitly sweep/credit unmatched balance
- Avoid
assertfor input/state validation that adversaries can trip (gas-exhausting failure modes on older compilers) - Document whether “donation” tokens are credited, ignored, or rejected
- Monitor raw balance vs internal ledger drift
Solve steps and PoC omitted.