Maren
GitHub
How it works

Redemptions

How a protocol redemption against the shared trove is split, value-neutrally, and how the H-2 reserve-excess edge was fixed.

Status: this mechanism is in the contract source and its audited test suite. It is not in the deployed matsnet contract. The vault at 0x46252B00AB59384518d9dB6D1f210ffF1221645b predates the redemption splitter entirely — reconcileRedemption, settleRedemption, collateralOf, redemptionCollateralPerShare, redemptionShortfall and pendingRedemptionCollateral are all absent from its dispatch table. Confirm it in one command:

bash
cast call 0x46252B00AB59384518d9dB6D1f210ffF1221645b "reconcileRedemption()" \
  --rpc-url https://rpc.test.mezo.org
# -> execution reverted, data: "0x"   (no dispatch entry)

Until the vault is redeployed, a protocol redemption against the pooled trove is not split by the mechanism described below. Everything on this page describes packages/contracts/src/MarenVault.sol and the two adversarial audits run against it: a design and audit record, not a description of live behaviour. Redeploying is a prerequisite for the vault holding real money, alongside the paid audit.

MUSD lets anyone redeem MUSD for BTC against the lowest-collateralised troves, at par. When that happens to the pooled trove, the trove loses collateral and sheds debt in one event, and the vault has to divide both sides across its users fairly. That is the job of the redemption splitter.

What a redemption does to the pool

In the contract source, a redemption removes collateral from the shared trove and cancels an equal value of its debt. Neither side belongs to any single user, so the splitter distributes both across debt shares: the collateral removed is charged pro rata, and the debt relief is credited pro rata.

The splitter is value-neutral by design. A user charged some BTC of collateral should receive an equal value of debt relief, so a redemption changes what a user holds but not what it is worth. The audit's regression tests assert this neutrality holds for a solvent debtor, both on a plain redemption and on one arriving after a recognised shortfall — against the source contract. It is not yet an assertion about deployed bytecode.

The relevant functions in source are reconcileRedemption, _syncState, redemptionCollateralPerShare, settleRedemption and collateralOf. None of them is present in the currently deployed vault. They were the primary target of the contracts audit of that source.

The bug that was found and fixed: H-1

The first version of the splitter had a High-severity flaw. When a redemption produced a shortfall (an uncollectable debit from a position below 100% collateralisation), the contract correctly recorded the shortfall rather than papering over it, but then re-read that same recorded shortfall on the next sync as if it were a brand new redemption.

The effect was a phantom redemption charged pro rata to every solvent debtor, repeatedly, with no debt relief attached, until the shortfall was fully socialised onto the solvent users. Both entrypoints that drive it are permissionless and need no price, so any passer-by could grind the loop. In the measured Foundry reproduction against the source contract, 0.03364 BTC was drained from a solvent debtor with nothing given in return.

The fix routes both the detector and the preview through one function that subtracts the recorded shortfall before comparing the books against the trove, saturating so it cannot underflow. Two regression tests, both proven to fail against the pre-fix contract, pin it: one grinds both permissionless entrypoints ten times and asserts no phantom is booked, the other asserts a genuine redemption arriving after a shortfall is still measured at full size.

The reserve-excess edge, and how it was fixed: H-2

An adversarial audit found one High-severity edge here, and it has since been fixed in source. The fix has not been deployed.

The mechanism: debt relief is capped by the vault's MUSD reserve (outstandingDebt = troveNetDebt - reserveMUSD), but the collateral debit was not. When a redemption cancelled more trove debt than the pool's users actually owed, which needs a non-zero reserve and a large redemption, users were charged collateral for relief that landed in the reserve, where no user has a direct claim on it.

The loss was bounded: at most reserveMUSD at the instant the redemption lands, because the excess relief is exactly the part the reserve was already covering.

The fix in source: the excess is absorbed by the protocol's own position instead of being split across users, so each user loses collateral worth exactly the debt they stopped owing, and the per-position value-neutrality claim is strictly true again. depositProtocolCollateral retires any resulting shortfall, which is the make-whole path the natspec had always promised. The pinning test was inverted to assert users are made whole and proven to fail against the pre-fix code.

Residual left for the paid audit: if the protocol's own position is exhausted by a large excess, the remainder falls to the shortfall path. It is bounded and recorded, not silent, and the make-whole path can retire it. This is the honest state — and the honest state also includes that none of this reconciliation is live on matsnet yet.