# buyoutLien() will cause the vault to fail to processEpoch()

LienToken.buyoutLien transfers a lien without decrementing the vault's liensOpenForEpoch counter, so processEpoch's zero-check reverts and epoch processing is bricked.

- Payout: Contest reward
- Severity: high
- Program: Astaria
- Credited: bin2chen
- Disclosed: 2022-11-07
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2022-10-astaria-judging/issues/245
- Library page: https://bugbountylibrary.com/r/sherlock%3A2022-10-astaria%3AH-3
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error

**Target:** LienToken / PublicVault epoch accounting (Solidity)
**Root cause:** buyoutLien transfers lien ownership to a new receiver but never calls decreaseEpochLienCount on the source public vault, leaving liensOpenForEpoch[currentEpoch] non-zero.
**Steps:**
1. Create a lien in a public vault so liensOpenForEpoch[currentEpoch] increments.
2. Call `buyoutLien(params)` with a receiver, transferring the lien out of the vault without decrementing the counter.
3. Call `processEpoch()`; it checks `liensOpenForEpoch[currentEpoch] == 0` and reverts, blocking epoch processing.
**How found:** Code reading of the increment/decrement symmetry: createLien increments and repay/liquidate decrement liensOpenForEpoch, but buyoutLien's _transfer path omits the decrement, breaking processEpoch's zero invariant.
**Exploitation:** Any lien buyout leaves a stale open-lien count; the vault's processEpoch then reverts, halting epoch settlement/withdrawals for that vault.
**Insight:** When a counter gates a state transition (epoch processing requires count==0), audit every path that moves the underlying object (transfer/buyout) for a matching decrement, not just create/repay/liquidate.
