Audits
Three adversarial self-audits — two of Maren's own contracts, one against Mezo's live bytecode — what they found, and what a paid audit gates.
Before anything went out, three adversarial audits ran: two against Maren's own contracts, and one
against Mezo's live bytecode. They found real bugs, which is the point. Each report names what was
attacked and held, not only what broke. The reports live in docs/audit/ in the repository, which
is private during the grant review and opens with the paid audit.
These are pre-audit hardening passes by the author's own tooling, not a substitute for a paid
third-party audit. A paid audit gates mainnet. No Maren contract reaches mainnet before an
independent audit of MarenVault, MarenEarn and MarenRelayHub — Earn holds user principal in
a pool that can lose it, which puts it in scope — with findings and remediations published.
The fixes below are fixed in source, not on chain. The contract deployed to matsnet
(0x46252B00…645b) predates the redemption splitter: reconcileRedemption, settleRedemption,
collateralOf and redemptionShortfall are all absent from its dispatch table, verifiable with
cast code. Until that build is replaced, a redemption against the pooled trove would go
unreconciled. Only testnet BTC is exposed. Redeploying is a prerequisite for any mainnet claim.
The three audits
MarenVault and the redemption splitter. A permissionless fund-drain (H-1) and a bounded High
(H-2), both found and fixed in source; both fixes are still pending redeployment to matsnet.
Every selector Maren calls checked against the deployed bytecode. Two bugs found and fixed.
The relayer, forwarder, and web relay client. A budget-halt denial of service fixed.
Contracts audit
Scope was MarenVault and the redemption splitter, measured against Mezo's own source
(MEZO-GROUND-TRUTH.md) and the SDK's divergence records.
H-1 (FIXED IN SOURCE, NOT YET DEPLOYED): a shortfall re-read as a phantom redemption
A recognised redemption shortfall was re-read on the next sync as a fresh redemption and charged pro rata to every solvent debtor, repeatedly, with no relief attached, until the shortfall was fully socialised. Both entrypoints are permissionless and need no price, so any passer-by could grind the loop; the measured Foundry reproduction drained 0.03364 BTC from a solvent debtor (about $2,122 at the test fixture's $63,072 BTC price — the dollar figure moves with BTC, the 0.03364 does not). Fixed by routing the detector and preview through one function that subtracts the recorded shortfall before comparing books with trove. Two regression tests, both proven to fail against the pre-fix contract.
H-2 (FIXED IN SOURCE, NOT YET DEPLOYED): relief the reserve over-covers is absorbed by the protocol
When a redemption cancels more trove debt than the pool's users owe, which needs a non-zero
MUSD reserve, users were charged collateral for relief that landed in the reserve where no user
has a direct claim. The loss was bounded by reserveMUSD at the instant of redemption.
Fixed by having the protocol's own position absorb that excess instead of splitting it across
users, so each user loses collateral worth exactly the debt they stopped owing. The pinning
test was inverted to assert users are made whole, and proven to fail against the pre-fix code.
Residual for the paid audit: if the protocol's own position is exhausted, the remainder falls
to the shortfall path. See Redemptions.
Lower-severity items
Several Medium and Info items are documented (an admin-path gap on a non-active trove, an unbounded per-share growth as debt shares shrink) and two Info items fixed with guards and pinned tests. Each carries a reproduction or an argument.
The audit also records what was attacked and held, including the interest-first ordering question the ground-truth file headlines, verified correct under a proof rather than assumed.
Mezo conformance audit
The question: does Maren integrate with Mezo and MUSD correctly, against the contracts actually deployed rather than the documentation? Audited 19 August 2026 against both networks, working at the dispatch table: for each proxy the EIP-1967 implementation slot was read, the implementation bytecode fetched, and the 4-byte selector of every function Maren declares searched for inside it.
| Verdict | Count | Where |
|---|---|---|
| PASS | 64 | Selectors, divergences, doc discrepancies, hints, oracle, precompiles |
| DRIFTED | 6 | Recovery Mode, a payment event topic, an unread staleness flag, three byte counts |
| UNPROVEN | 3 | Refinance-fee arithmetic, circulating-vs-backed ratio, MEZO token precompile |
Every one of the 44 function selectors Maren declares exists on the deployed contract with the argument types Maren encodes, on both networks. Two bugs were found and fixed:
Recovery Mode blocks more than recorded
Read out of the deployed BorrowerOperations bytecode: in Recovery Mode, borrow and
collateral withdrawal are closed outright and revert with a bare Error(string). Maren had no
defence at any layer. Fixed, with a test.
A payment event with a phantom parameter
A PaidToHandle event signature hashed to a topic the chain never emits, silently dropping
every handle payment from Activity. Fixed, with a test.
Negative controls are part of what makes this pass stronger than a getter check: every
Liquity-shaped variant carrying _maxFeePercentage was searched for too, and confirmed absent
on both networks. A claim that a parameter does not exist is only worth something if the method
could have found it.
Meta-transaction audit
Scope was the forwarder and relay hub contracts, the whole relayer service, and the web relay
client, read against ground truth with live cast calls where a claim could be settled on-chain.
High (FIXED): a signer-chosen gas ceiling latches the daily budget halt
The day-long budget halt latched on committed spend debited with request.gas, a ceiling the
signer picks, and reconciliation never re-read the latch. One request signing 1,000,000 gas
against a budget sized for it took the relayer offline for the rest of the day, though the
transaction settled at 120,000 gas, and it costs nothing to do on purpose. Fixed: the halt is
lifted when reconciliation shows committed spend back under the limit, with three regression
tests.
Medium/Low fixed items
Calldata gas moved inside the signed reservation; a failed reservation now refunded; the hub validates before calling an arbitrary address; the web client no longer believes a 202 on its hash alone; the relayer URL must not be plaintext.
Documented items
executeWithFee has no fee-token allowlist (needs a contract redeploy); the free tier is
Sybilable and the daily BTC cap is the real bound; health endpoints disclose posture. Each is
documented with its bound.
The relayer's four adversarial rounds were structured attacks on Maren's own design. Round two found a budget race allowing 52x overspend; round three found the fix created a denial-of-service path; round four found the CI had never actually exercised the relayer's code. Each finding is fixed and regression-tested.
What holds every fix honest
Every fix was verified to fail against the unfixed code, by reverting the change and re-running the suite. That is the discipline behind the whole product: a claim is only as good as the test that would break if it were false.
