Crypto Training
Liquidation as a Security Property: Fairness, Liveness, and Solvency
Liquidation logic is often treated as pure economics. In practice, it is a security boundary where liveness failures and asymmetry bugs convert stress into protocol loss.
Liquidation systems are security systems.
They decide who can force balance-sheet transitions under stress.
flowchart LR
A[Price move] --> B[Position unhealthy]
B --> C[Liquidation callable]
C --> D[Repay + seize collateral]
D --> E[Protocol solvency restored]
C --> F[If blocked: bad debt accumulates]
Security dimensions of liquidation design#
| Dimension | Question |
|---|---|
| Liveness | Can healthy liquidations still execute under stress? |
| Fairness | Can borrowers repair positions before forced close? |
| Solvency | Does completed liquidation actually reduce system risk? |
Failure patterns observed repeatedly#
- Token transfer restrictions block seizure transfers.
- Pause controls freeze borrower repair but leave liquidations active.
- Fixed bonus math makes deep positions unliquidatable.
- Callback-based integrations allow liquidation-step reentrancy/DoS.
Control-flow hardening#
stateDiagram-v2
[*] --> Healthy
Healthy --> Warning: healthFactor < warn
Warning --> Recovering: borrower repay
Warning --> Liquidating: keeper call
Liquidating --> Settled: repay and seize success
Liquidating --> Blocked: transfer/callback failure
Blocked --> EmergencyPath: governance mitigation
Settled --> Healthy
Safer liquidation function skeleton#
function liquidate(address user, uint256 repayAmount) external {
_refreshOracle();
require(_isLiquidatable(user), "not-liquidatable");
require(repayAmount > 0, "zero-repay");
uint256 beforeDebt = debtOf[user];
_pullDebtAsset(msg.sender, repayAmount);
uint256 applied = _applyRepay(user, repayAmount);
uint256 seize = _computeSeize(applied); // bounded rounding policy
_seizeCollateral(user, msg.sender, seize);
require(debtOf[user] < beforeDebt, "no-debt-progress");
}
The key line is final progress assertion: liquidation must strictly move risk in the correct direction.
Test cases that matter most#
| Test | Expected result |
|---|---|
| paused market + repay attempt | repay path available or explicit safe policy |
| blocklisted collateral recipient | graceful fallback, no partial-accounting corruption |
| extreme price gap | no arithmetic overflow/underflow, no revert traps |
| repeated micro-liquidations | no rounding-based value extraction |
Operator playbook#
- Maintain emergency liquidation fallback strategy.
- Monitor liquidation fail rate by reason code.
- Simulate outage scenarios with mainnet-like constraints.
- Run post-incident fairness review, not just solvency review.