Evidence
Planted-bug methodology
Tests that pass prove little on their own. To show the suite catches real mistakes, a published harness plants one bug at a time in the contracts, runs the full suite, records whether anything failed, and restores the source.
Result: 24 of 25 planted bugs caught. Re-run on 2026-10-03 on commit 8b698f6; same result as the first run.
How it works
script/planted-bugs.sh in the repo:
- Copies
src/TorqueMarket.solandsrc/TorqueVault.solaside. - For each mutation, replaces one exact piece of source text (it fails loudly if the text is not found, so a mutation can never silently do nothing).
- Runs every unit, adversarial and invariant test, without the fork tests.
- Counts failing unit/adversarial tests and failing invariants. If both are zero, the bug survived.
- Restores both files and moves to the next mutation.
LOG=research/planted-bugs.log ./script/planted-bugs.sh
The latest log is research/planted-bugs.log.
The 25 mutations
| # | Bug planted | Result |
|---|---|---|
| M1 | Knock-out ignores a stale feed | caught |
| M2 | No utilisation cap | caught |
| M3a | Vault cap check in _deposit removed | survived |
| M3b | Vault cap removed (both checks) | caught |
| M4 | Loans marked at face value | caught |
| M5 | Vault shorted on knock-out | caught |
| M6 | Open allowed on a stale feed | caught |
| M7 | Financing not accrued | caught |
| M8 | Knock-out level without the 5% buffer | caught |
| M10 | Close allowed while underwater | caught |
| M11 | Open fill guard removed | caught |
| M12 | Open-interest cap removed | caught |
| M13 | Opens skip the pool check | caught |
| M14 | Knock-outs skip the pool check | caught |
| M15 | LP flows skip the pool check | caught |
| M16 | Loan mark ignores the pool average | caught |
| M17 | Strict knock-out rule (no recency exemption) | caught |
| M18 | Agreement band ten times wider | caught |
| M19 | Tick math sign flipped | caught |
| M20 | Unwind without the dead-feed check | caught |
| M21 | LP exits ignore price checks with loans open | caught |
| M22 | Dead-feed clock never resets on report | caught |
| M23 | Feed read reverts instead of "no price" | caught |
| M24 | Open does not clear the dead-feed clock | caught |
| M25 | Reentrancy guard removed from open and close | caught |
The one survivor
M3a removes one of two identical cap checks: the vault cap is enforced in maxDeposit / maxMint and again in _deposit. With one copy gone, behaviour is unchanged, so no test can fail. M3b removes both, and it is caught. A survivor that changes nothing is the expected outcome for a deliberately redundant check.