# audit-unfair-liquidation

Audits Solidity liquidation mechanisms for unfair liquidation vulnerabilities including missing L2 sequencer grace periods, interest accumulation while paused, repayment paused while liquidation active, late interest/fee updates, lost positive PNL/yield during liquidation, unhealthier post-liquidation state from cherry-picking, corrupted collateral priority, borrower replacement misattribution, no LTV gap allowing immediate liquidation, interest during auctions, and no liquidation slippage protection (project)

- **Kind:** skill
- **Source:** https://github.com/auditmos/skills
- **Page:** https://forefy.com/skills/45a9ee23-da61-4e4e-80b8-ba43d2b009d4
- **API (JSON + files):** https://forefy.com/api/asr/45a9ee23-da61-4e4e-80b8-ba43d2b009d4

---

## SKILL.md

---
name: audit-unfair-liquidation
description: Audits Solidity liquidation mechanisms for unfair liquidation vulnerabilities including missing L2 sequencer grace periods, interest accumulation while paused, repayment paused while liquidation active, late interest/fee updates, lost positive PNL/yield during liquidation, unhealthier post-liquidation state from cherry-picking, corrupted collateral priority, borrower replacement misattribution, no LTV gap allowing immediate liquidation, interest during auctions, and no liquidation slippage protection (project)
allowed-tools: Read, Grep, Glob
license: MIT
compatibility: Designed for Claude Code (or similar products)
metadata:
  author: Tomasz Kowalczyk (tom@auditmos.com)
  version: "1.0"
---

# Unfair Liquidation Auditor

## When to Use
- Auditing liquidation fairness, L2 deployments, pause mechanisms
- User mentions: L2 sequencer, grace period, pause, interest accumulation, LTV gap, auction, slippage protection, collateral priority
- Analyzing liquidation timing, state synchronization, user protections
- Reviewing pause/unpause logic, sequencer checks, health score calculations

## Audit Workflow

**IMPORTANT: Announce skill usage at the start of analysis**

Begin with: "I'm using the **audit-unfair-liquidation** skill to analyze this contract for unfair liquidation vulnerabilities..."

1. **Scan for liquidation fairness issues**
   - Search: `sequencer`, `paused`, `accrue`, `LTV`, `auction`, `healthFactor`, `slippage`, `collateralPriority`, `borrower`
   - Focus: sequencer checks, pause states, interest accrual, health calculations, auction mechanics

2. **Check against vulnerability patterns**
   - Reference `reference.md` for complete checklist
   - Compare code against `example.md`

3. **Validate exploitability**
   - **Check access control first** - grep for `onlyOwner|onlyAdmin|onlyGovernance` modifiers
   - Can non-privileged actors exploit unfair liquidation mechanisms?
   - Can users be liquidated during sequencer downtime without grace period?
   - Does interest accumulate while repayments paused?
   - Can liquidators cherry-pick stable collateral?
   - Is there an LTV gap between borrow and liquidation?
   - Verify no compensating protections exist
   - Downgrade severity if admin-only unless direct borrower harm

4. **Generate report**
   - Use deliverable template below
   - Include timing analysis and PoC
   - Rank by severity

## Core Vulnerability Patterns

See `reference.md` for full checklist. Key patterns:

1. Missing L2 sequencer grace period → users liquidated immediately when sequencer restarts
2. Interest accumulates while paused → users liquidated for interest accrued during downtime
3. Repayment paused, liquidation active → users prevented from avoiding liquidation
4. Late interest/fee updates → isLiquidatable uses stale values
5. Lost positive PNL/yield → profitable positions lose gains during liquidation
6. Unhealthier post-liquidation → liquidator cherry-picks stable collateral
7. Corrupted collateral priority → liquidation order doesn't match risk
8. Borrower replacement misattribution → original borrower repays new owner's debt
9. No LTV gap → users liquidatable immediately after borrowing
10. Interest during auction → borrowers accrue interest while being auctioned
11. No liquidation slippage protection → liquidators can't specify minimum rewards

**Code examples:** See `example.md`

## Severity Criteria

**Critical:** Missing sequencer grace period on L2, repayment paused while liquidation active, immediate liquidation after borrow (no LTV gap), **MUST be exploitable by non-privileged actors**
**High:** Interest accumulation during pause, late fee updates, cherry-picking collateral leaving unhealthier state, **MUST be exploitable by non-privileged actors**
**Medium:** Lost PNL/yield during liquidation, interest accrual during auctions, no liquidator slippage protection, **admin-only liquidation timing configuration issues with cascading borrower impact**
**Low:** Suboptimal collateral priority without security impact, **admin-only parameter issues without immediate borrower impact**

**IMPORTANT:** Admin-only liquidation timing functions (onlyOwner, onlyAdmin, onlyGovernance) are **MEDIUM or LOW severity** unless:
- Admin can trigger liquidations during sequencer downtime without grace period
- Pause mechanism controlled by admin creates asymmetry (repayment paused, liquidation active)
- LTV configuration by admin allows immediate liquidation after borrowing

## False Positives - Do NOT Flag

- L1-only deployments (no sequencer concerns)
- Protocols with explicit admin-only liquidation during pause
- Systems where pause simultaneously halts interest and liquidation
- Documented grace periods after unpause events
- Single-collateral systems (no cherry-picking possible)
- **Admin-only pause functions** (onlyOwner, onlyAdmin) where pause halts both repayment and liquidation symmetrically
- Governance-controlled LTV parameters with documented gap between borrow and liquidation thresholds
- Admin functions for grace period configuration with reasonable defaults

## Deliverable Format

**MANDATORY:** Before deliverable, verify each `checklist.md` item against codebase. Flag violations as findings.

Use template: `templates/report-template.md`

Each finding includes: severity, pattern #, file/lines, description, vulnerable code, timing/fairness analysis, PoC, remediation.

## Key Principles

- **Fairness** - users must have opportunity to avoid liquidation
- **Synchronization** - pause states must be consistent (repay ↔ liquidate)
- **Grace periods** - time for users to respond after downtime
- **Health improvement** - liquidation must improve borrower health
- **Predictability** - liquidators need slippage protection

## Output Guidelines

**DO:**
- Reference specific lines and functions
- Provide timing analysis (sequencer downtime windows)
- Show PoCs demonstrating unfair liquidation scenarios
- Analyze pause state interactions
- Calculate LTV gaps and health score changes

**DON'T:**
- Report intentional pause-based liquidation designs
- Flag missing features with alternative mechanisms
- Use vague terms ("might be unfair")
- Ignore documented grace period configurations

## checklist.md

# Unfair Liquidation Security Checklist

Verify each item before finalizing audit report:

- [ ] **L2 sequencer grace period:** Grace period implemented after sequencer restart before liquidations enabled
- [ ] **Interest during pause:** Interest accrual paused when repayments paused, OR liquidation also paused
- [ ] **Synchronized pause states:** Repayment pause also pauses liquidation to prevent unfair liquidations
- [ ] **Fee updates before check:** All interest/fees accrued before `isLiquidatable()` evaluation
- [ ] **PNL/yield credit:** Positive unrealized PNL and earned yield credited during liquidation settlement
- [ ] **Health improvement:** Liquidation improves borrower health score, not just extracts value
- [ ] **Risk-based priority:** Collateral liquidated in order of risk (volatile before stable)
- [ ] **Position transfer handling:** Repayments routed correctly after position ownership transfer
- [ ] **LTV gap exists:** Gap between max borrow LTV and liquidation threshold (e.g., 80% borrow, 85% liquidate)
- [ ] **Auction interest pause:** Interest paused during liquidation auction period
- [ ] **Liquidator slippage:** Liquidation accepts minReward/maxDebt for slippage protection

## example.md

# Unfair Liquidation Vulnerability Examples

## Pattern #1: Missing L2 Sequencer Grace Period

### VULNERABLE
```solidity
contract VulnerableL2Lending {
    ISequencerUptimeFeed public sequencerFeed;

    function liquidate(address user) external {
        (, int256 answer, , , ) = sequencerFeed.latestRoundData();

        // ISSUE: Only checks if sequencer is up, no grace period
        require(answer == 0, "Sequencer down");

        // Users liquidated immediately when sequencer restarts
        // No time to respond to price changes during downtime
        require(isLiquidatable(user), "Not liquidatable");
        _executeLiquidation(user);
    }
}
```

### FIXED
```solidity
contract FixedL2Lending {
    ISequencerUptimeFeed public sequencerFeed;
    uint256 public constant GRACE_PERIOD = 1 hours;

    function liquidate(address user) external {
        (, int256 answer, uint256 startedAt, , ) = sequencerFeed.latestRoundData();

        require(answer == 0, "Sequencer down");

        // Grace period after sequencer restart
        uint256 timeSinceUp = block.timestamp - startedAt;
        require(timeSinceUp >= GRACE_PERIOD, "Grace period active");

        // Users have 1 hour to add collateral or repay after restart
        require(isLiquidatable(user), "Not liquidatable");
        _executeLiquidation(user);
    }
}
```

## Pattern #2: Interest Accumulates While Paused

### VULNERABLE
```solidity
contract VulnerableInterestAccrual {
    bool public repaymentsPaused;
    uint256 public lastAccrualTime;
    uint256 public accumulatedInterest;

    function accrueInterest() public {
        // ISSUE: Interest accrues even during pause
        uint256 elapsed = block.timestamp - lastAccrualTime;
        accumulatedInterest += calculateInterest(elapsed);
        lastAccrualTime = block.timestamp;
    }

    function repay(uint256 amount) external {
        require(!repaymentsPaused, "Repayments paused");
        // Users can't repay but interest keeps growing
        // They become liquidatable through no fault of their own
    }

    function liquidate(address user) external {
        accrueInterest();
        require(isLiquidatable(user), "Not liquidatable");
        // Liquidation allowed even during repayment pause
    }
}
```

### FIXED
```solidity
contract FixedInterestAccrual {
    bool public repaymentsPaused;
    uint256 public lastAccrualTime;
    uint256 public pauseStartTime;

    function accrueInterest() public {
        if (repaymentsPaused) {
            // Don't accrue during pause
            return;
        }

        uint256 elapsed = block.timestamp - lastAccrualTime;
        accumulatedInterest += calculateInterest(elapsed);
        lastAccrualTime = block.timestamp;
    }

    function pauseRepayments() external onlyOwner {
        repaymentsPaused = true;
        pauseStartTime = block.timestamp;
        // Interest stops accruing when pause begins
    }

    function unpauseRepayments() external onlyOwner {
        repaymentsPaused = false;
        // Reset accrual time to unpause time, skipping paused period
        lastAccrualTime = block.timestamp;
    }
}
```

## Pattern #3: Repayment Paused, Liquidation Active

### VULNERABLE
```solidity
contract VulnerableAsymmetricPause {
    bool public repaymentsPaused;
    bool public liquidationsPaused;

    function pauseRepayments() external onlyOwner {
        repaymentsPaused = true;
        // ISSUE: Liquidations remain active
        // Users have no way to defend their positions
    }

    function repay(uint256 amount) external {
        require(!repaymentsPaused, "Repayments paused");
        _processRepayment(amount);
    }

    function liquidate(address user) external {
        // Liquidation works even when repayments paused
        require(isLiquidatable(user), "Not liquidatable");
        _executeLiquidation(user);
    }
}
```

### FIXED
```solidity
contract FixedSymmetricPause {
    bool public operationsPaused;

    function pauseOperations() external onlyOwner {
        operationsPaused = true;
        // Both repayments AND liquidations paused together
    }

    function repay(uint256 amount) external {
        require(!operationsPaused, "Operations paused");
        _processRepayment(amount);
    }

    function liquidate(address user) external {
        require(!operationsPaused, "Operations paused");
        require(isLiquidatable(user), "Not liquidatable");
        _executeLiquidation(user);
    }
}
```

## Pattern #4: Late Interest/Fee Updates

### VULNERABLE
```solidity
contract VulnerableLateUpdate {
    mapping(address => uint256) public userDebt;
    uint256 public globalInterestIndex;

    // ISSUE: isLiquidatable uses stale debt values
    function isLiquidatable(address user) public view returns (bool) {
        // Uses cached debt without accruing pending interest
        return userDebt[user] > getCollateralValue(user) * 100 / 125;
    }

    function liquidate(address user) external {
        require(isLiquidatable(user), "Not liquidatable");

        // Interest accrued AFTER check - actual debt higher
        accrueInterest();
        updateUserDebt(user);

        // Liquidation may fail or behave unexpectedly
        _executeLiquidation(user);
    }
}
```

### FIXED
```solidity
contract FixedEarlyUpdate {
    mapping(address => uint256) public userDebt;
    uint256 public globalInterestIndex;

    function isLiquidatable(address user) public returns (bool) {
        // Accrue interest FIRST
        accrueInterest();
        updateUserDebt(user);

        return userDebt[user] > getCollateralValue(user) * 100 / 125;
    }

    function liquidate(address user) external {
        // isLiquidatable already accrued interest
        require(isLiquidatable(user), "Not liquidatable");
        _executeLiquidation(user);
    }
}
```

## Pattern #5: Lost Positive PNL/Yield

### VULNERABLE
```solidity
contract VulnerablePNLLoss {
    struct Position {
        uint256 collateral;
        uint256 debt;
        int256 unrealizedPnL;
        uint256 earnedYield;
    }

    function liquidate(address user) external {
        Position memory pos = positions[user];

        // ISSUE: Positive PnL and yield ignored during liquidation
        uint256 collateralToSeize = pos.debt * 105 / 100;

        // User loses their earned profits
        // Example: 1000 collateral, 800 debt, +200 PnL
        // Should only seize ~630 (800 - 200 + bonus)
        // Actually seizes 840 (ignores +200 PnL)

        _seizeCollateral(user, collateralToSeize);
        delete positions[user];
    }
}
```

### FIXED
```solidity
contract FixedPNLCredit {
    struct Position {
        uint256 collateral;
        uint256 debt;
        int256 unrealizedPnL;
        uint256 earnedYield;
    }

    function liquidate(address user) external {
        Position memory pos = positions[user];

        // Credit positive PnL and yield to effective collateral
        int256 effectiveValue = int256(pos.collateral) + pos.unrealizedPnL + int256(pos.earnedYield);

        // Calculate seizure from net position value
        uint256 debtWithBonus = pos.debt * 105 / 100;

        if (effectiveValue > int256(debtWithBonus)) {
            // User has equity - return excess
            uint256 excess = uint256(effectiveValue) - debtWithBonus;
            _returnToUser(user, excess);
        }

        _seizeCollateral(user, pos.collateral);
        delete positions[user];
    }
}
```

## Pattern #6: Unhealthier Post-Liquidation State

### VULNERABLE
```solidity
contract VulnerableCherryPick {
    struct Collateral {
        address token;
        uint256 amount;
    }

    mapping(address => Collateral[]) public userCollateral;

    // ISSUE: Liquidator chooses which collateral to seize
    function liquidate(address user, uint256 collateralIndex) external {
        Collateral storage col = userCollateral[user][collateralIndex];

        // Liquidator picks USDC (stable), leaves BTC (volatile)
        // User's remaining position is HIGHER risk than before
        _seizeCollateral(user, col.token, col.amount);
    }
}
```

### FIXED
```solidity
contract FixedCollateralPriority {
    struct Collateral {
        address token;
        uint256 amount;
        uint256 riskWeight; // Higher = riskier
    }

    mapping(address => Collateral[]) public userCollateral;

    function liquidate(address user) external {
        // Sort by risk weight descending
        // Liquidate riskiest collateral first
        Collateral[] storage cols = userCollateral[user];

        for (uint i = 0; i < cols.length; i++) {
            // Find highest risk collateral
            uint256 maxRiskIndex = _findHighestRisk(cols);

            _seizeCollateral(user, cols[maxRiskIndex].token, cols[maxRiskIndex].amount);

            // Check if enough liquidated
            if (!isLiquidatable(user)) break;
        }

        // Post-liquidation: User left with lower-risk collateral
        require(isHealthier(user), "Health must improve");
    }
}
```

## Pattern #9: No LTV Gap

### VULNERABLE
```solidity
contract VulnerableNoLTVGap {
    uint256 public constant MAX_LTV = 8000; // 80%
    uint256 public constant LIQUIDATION_THRESHOLD = 8000; // 80%

    function borrow(uint256 amount) external {
        uint256 collateralValue = getCollateralValue(msg.sender);
        uint256 newDebt = userDebt[msg.sender] + amount;

        // ISSUE: Can borrow up to exact liquidation threshold
        require(newDebt * 10000 / collateralValue <= MAX_LTV, "Exceeds LTV");

        userDebt[msg.sender] = newDebt;
    }

    function isLiquidatable(address user) public view returns (bool) {
        // Any price movement immediately triggers liquidation
        return userDebt[user] * 10000 / getCollateralValue(user) > LIQUIDATION_THRESHOLD;
    }

    // Result: Borrow at 80% LTV, any price drop = instant liquidation
    // User has zero margin for error
}
```

### FIXED
```solidity
contract FixedLTVGap {
    uint256 public constant MAX_LTV = 7500; // 75% max borrow
    uint256 public constant LIQUIDATION_THRESHOLD = 8500; // 85% liquidation

    function borrow(uint256 amount) external {
        uint256 collateralValue = getCollateralValue(msg.sender);
        uint256 newDebt = userDebt[msg.sender] + amount;

        require(newDebt * 10000 / collateralValue <= MAX_LTV, "Exceeds LTV");

        userDebt[msg.sender] = newDebt;
    }

    function isLiquidatable(address user) public view returns (bool) {
        return userDebt[user] * 10000 / getCollateralValue(user) > LIQUIDATION_THRESHOLD;
    }

    // 10% gap: User can borrow at 75%, has buffer before 85% liquidation
    // ~13% price drop needed before liquidation (not immediate)
}
```

## Pattern #10: Interest During Auction

### VULNERABLE
```solidity
contract VulnerableAuctionInterest {
    struct Auction {
        address borrower;
        uint256 startTime;
        uint256 startDebt;
    }

    mapping(uint256 => Auction) public auctions;

    function startAuction(address user) external {
        require(isLiquidatable(user), "Not liquidatable");

        auctions[nextAuctionId++] = Auction({
            borrower: user,
            startTime: block.timestamp,
            startDebt: userDebt[user] // Records debt at start
        });
    }

    function settleAuction(uint256 auctionId) external {
        Auction memory auction = auctions[auctionId];

        // ISSUE: Interest continued accruing during 24h auction
        accrueInterest();
        uint256 currentDebt = userDebt[auction.borrower];

        // currentDebt > startDebt due to interest
        // Auction proceeds may not cover inflated debt
    }
}
```

### FIXED
```solidity
contract FixedAuctionInterest {
    struct Auction {
        address borrower;
        uint256 startTime;
        uint256 frozenDebt; // Interest frozen at auction start
    }

    mapping(uint256 => Auction) public auctions;
    mapping(address => bool) public inAuction;

    function startAuction(address user) external {
        require(isLiquidatable(user), "Not liquidatable");

        // Freeze interest at auction start
        accrueInterest();
        inAuction[user] = true;

        auctions[nextAuctionId++] = Auction({
            borrower: user,
            startTime: block.timestamp,
            frozenDebt: userDebt[user]
        });
    }

    function accrueInterest() public {
        for (address user : activeUsers) {
            // Skip users in auction - their debt is frozen
            if (inAuction[user]) continue;
            _accrueForUser(user);
        }
    }

    function settleAuction(uint256 auctionId) external {
        Auction memory auction = auctions[auctionId];
        // Use frozen debt amount, not current inflated amount
        _settleLiquidation(auction.borrower, auction.frozenDebt);
        inAuction[auction.borrower] = false;
    }
}
```

## Pattern #11: No Liquidation Slippage Protection

### VULNERABLE
```solidity
contract VulnerableNoSlippage {
    function liquidate(address user, uint256 debtToCover) external {
        require(isLiquidatable(user), "Not liquidatable");

        // ISSUE: No slippage protection
        // MEV bot can sandwich this transaction
        uint256 reward = calculateReward(debtToCover);

        // Between submission and execution:
        // - Price changes
        // - Other liquidators front-run
        // - Reward changes unexpectedly

        token.transferFrom(msg.sender, address(this), debtToCover);
        collateral.transfer(msg.sender, reward);
    }
}
```

### FIXED
```solidity
contract FixedWithSlippage {
    function liquidate(
        address user,
        uint256 debtToCover,
        uint256 minReward,
        uint256 maxDebtAccepted
    ) external {
        require(isLiquidatable(user), "Not liquidatable");

        uint256 actualDebt = getActualDebt(user);
        require(actualDebt <= maxDebtAccepted, "Debt changed");

        uint256 reward = calculateReward(debtToCover);
        require(reward >= minReward, "Reward below minimum");

        // Liquidator protected from:
        // - Unexpected debt increases
        // - Reward reduction from front-running
        // - Price manipulation

        token.transferFrom(msg.sender, address(this), debtToCover);
        collateral.transfer(msg.sender, reward);
    }
}
```

## Summary: Key Protections

1. **L2 grace period:** 1 hour minimum after sequencer restart
2. **Synchronized pause:** Repayment pause = liquidation pause
3. **Interest freeze:** Stop accrual during pause and auction
4. **Early updates:** Accrue all fees before liquidation check
5. **PNL credit:** Include unrealized gains in liquidation math
6. **Health improvement:** Verify borrower health improves
7. **Risk priority:** Liquidate volatile collateral first
8. **LTV gap:** 10%+ gap between borrow and liquidation LTV
9. **Slippage protection:** Accept minReward/maxDebt parameters

## reference.md

# Unfair Liquidation Vulnerability Patterns

## Pattern #1: Missing L2 Sequencer Grace Period
**Risk:** Users on L2 chains (Arbitrum, Optimism) liquidated immediately when sequencer comes back online, with no time to respond to price changes during downtime
**Detection:** Check for sequencer uptime oracle integration and grace period after sequencer restart
**Impact:** Mass unfair liquidations after sequencer downtime, users unable to add collateral or repay

## Pattern #2: Interest Accumulates While Paused
**Risk:** Interest/fees continue accruing while protocol paused, causing users to become liquidatable without ability to repay during pause
**Detection:** Verify interest accrual stops when repayment paused, or liquidation also paused
**Impact:** Users liquidated for debt they couldn't have repaid during downtime

## Pattern #3: Repayment Paused, Liquidation Active
**Risk:** Protocol pauses repayments (e.g., for upgrade) but liquidation remains active, preventing users from avoiding liquidation
**Detection:** Check if repayment pause state also disables liquidation
**Impact:** Guaranteed unfair liquidations - users cannot defend positions

## Pattern #4: Late Interest/Fee Updates
**Risk:** `isLiquidatable()` check uses stale interest values, not calling `accrueInterest()` first
**Detection:** Verify all fee/interest accumulators updated before liquidation eligibility check
**Impact:** Users liquidated based on stale data, or liquidations fail when actual values differ

## Pattern #5: Lost Positive PNL/Yield
**Risk:** Profitable positions with unrealized gains or earned yield lose these during liquidation
**Detection:** Check if positive PNL/yield credited to borrower during liquidation settlement
**Impact:** Users lose earned profits, liquidation takes more than necessary

## Pattern #6: Unhealthier Post-Liquidation State
**Risk:** Liquidator cherry-picks stable collateral (USDC, WETH), leaving borrower with only volatile assets
**Detection:** Verify liquidation improves health score or follows risk-based collateral priority
**Impact:** Users left with worse risk profile, cascading liquidations more likely

## Pattern #7: Corrupted Collateral Priority
**Risk:** Liquidation order doesn't match risk profile - volatile assets should be liquidated first
**Detection:** Check if collateral liquidation follows risk-weighted priority (volatile before stable)
**Impact:** Protocol accumulates higher-risk collateral, increases systemic risk

## Pattern #8: Borrower Replacement Misattribution
**Risk:** After position transfer, original borrower's repayments credited to new owner
**Detection:** Check repayment routing when positions are transferable
**Impact:** Original borrower loses funds, new owner gets free repayment

## Pattern #9: No LTV Gap
**Risk:** Borrow LTV equals liquidation LTV, so positions can be liquidated immediately after borrowing on any price movement
**Detection:** Verify gap between maximum borrow LTV and liquidation threshold
**Impact:** Users liquidated before having opportunity to manage position

## Pattern #10: Interest During Auction
**Risk:** Borrowers continue accruing interest while their position is being auctioned for liquidation
**Detection:** Check if interest pauses during auction period
**Impact:** Auction proceeds may not cover debt if interest continues growing

## Pattern #11: No Liquidation Slippage Protection
**Risk:** Liquidators cannot specify minimum acceptable rewards, MEV can sandwich liquidation transactions
**Detection:** Check if liquidation functions accept minReward/maxDebt parameters
**Impact:** Liquidators receive less than expected, reduces liquidation reliability

## templates

```

```

## templates/report-template.md

# Unfair Liquidation Security Audit Report

## Executive Summary

**Contract:** [Contract Name]
**Audit Date:** [Date]
**Auditor:** [Name/Team]

**Findings Overview:**
- Critical: X
- High: X
- Medium: X
- Low: X

## Findings

---

### [SEVERITY] Finding #X: [Vulnerability Title]

**Pattern:** #X - [Pattern Name from reference.md]

**Location:** `[contract_name.sol:line_numbers]`

**Description:**

[Detailed explanation of the unfair liquidation vulnerability]

**Vulnerable Code:**

```solidity
// Highlight the problematic mechanism
function liquidate(address user) external {
    // Show the specific issue
}
```

**Timing/Fairness Analysis:**

[Analyze the unfairness:]
- **User impact:** [How users are unfairly affected]
- **Time window:** [Window where unfairness occurs]
- **User recourse:** [Can users defend? Why/why not]
- **Severity multiplier:** [Mass liquidations vs individual]

**Proof of Concept:**

```solidity
contract PoC {
    function testUnfairLiquidation() public {
        // 1. Setup: User creates healthy position
        // 2. Trigger: Pause/sequencer downtime/price change
        // 3. Exploit: User liquidated without opportunity to respond
        // 4. Demonstrate: User had no recourse
    }
}
```

**Scenario:**
1. [User creates position at X% LTV]
2. [Event occurs - pause/downtime/etc]
3. [User becomes liquidatable during event]
4. [User cannot repay/add collateral]
5. [User liquidated unfairly]

**Impact Analysis:**

**Direct Impact:**
- [Immediate effect - e.g., "Users liquidated without notice"]

**Systemic Impact:**
- [Protocol-wide effect - e.g., "Mass liquidations after sequencer restart"]

**Scale:**
- [Quantify affected users - e.g., "All L2 users during any sequencer downtime"]

**Remediation:**

```solidity
function liquidate(address user) external {
    // Add grace period check
    require(block.timestamp >= gracePeriodEnd, "Grace period active");

    // Ensure synchronized pause states
    require(!repaymentsPaused, "Operations paused");

    // Verify health improvement
    uint256 healthBefore = getHealthFactor(user);
    _executeLiquidation(user);
    require(getHealthFactor(user) > healthBefore, "Must improve health");
}
```

**Recommendations:**
1. [Primary fix - e.g., "Add 1 hour grace period after sequencer restart"]
2. [Secondary fix - e.g., "Synchronize repayment and liquidation pause states"]

---

### [SEVERITY] Finding #X: [Next Vulnerability]

[Repeat above structure for each finding]

---

## Severity Definitions

**Critical:** Missing L2 sequencer grace period enabling mass liquidations, repayment paused while liquidation active preventing any user defense, zero LTV gap allowing immediate liquidation after borrow.

**High:** Interest accumulation during pause causing unfair debt growth, late fee updates causing stale liquidation checks, cherry-picking stable collateral leaving users with worse risk profile.

**Medium:** Lost positive PNL/yield during liquidation, interest accrual during auction period, missing liquidator slippage protection.

**Low:** Suboptimal collateral priority without security impact, minor timing issues.

## Recommendations Summary

### Immediate Actions (Critical/High)
1. [List critical fixes]
   - Example: "Implement L2 sequencer grace period (1 hour minimum)"
   - Example: "Synchronize repayment and liquidation pause states"

### Short-term Improvements (Medium)
1. [List medium-priority enhancements]
   - Example: "Credit positive PNL during liquidation"
   - Example: "Add liquidator slippage protection"

### Long-term Enhancements (Low)
1. [List optimization opportunities]
   - Example: "Implement risk-weighted collateral priority"

## Checklist Results

Based on `checklist.md`:

- [x] **L2 sequencer grace period:** Implemented after sequencer restart ✓/✗
- [x] **Interest during pause:** Paused or liquidation also paused ✓/✗
- [x] **Synchronized pause states:** Repayment pause disables liquidation ✓/✗
- [x] **Fee updates before check:** Interest accrued before isLiquidatable ✓/✗
- [x] **PNL/yield credit:** Positive values credited during liquidation ✓/✗
- [x] **Health improvement:** Liquidation improves borrower health ✓/✗
- [x] **Risk-based priority:** Volatile collateral liquidated first ✓/✗
- [x] **Position transfer handling:** Repayments routed correctly ✓/✗
- [x] **LTV gap exists:** Gap between borrow LTV and liquidation threshold ✓/✗
- [x] **Auction interest pause:** Interest frozen during auction ✓/✗
- [x] **Liquidator slippage:** minReward/maxDebt parameters accepted ✓/✗

## Timing Analysis

### L2 Sequencer Scenarios
- **Average downtime:** [X minutes/hours historical data]
- **Max downtime:** [Worst case scenario]
- **Liquidations during restart:** [Potential volume]
- **Recommended grace period:** [X hours based on analysis]

### Pause Duration Impact
- **Typical pause length:** [Upgrade windows]
- **Interest accrual:** [$ per hour during pause]
- **Positions affected:** [% near liquidation threshold]

### LTV Gap Analysis
- **Current gap:** [X%]
- **Price movement to liquidation:** [X% drop needed]
- **Recommended gap:** [X% based on volatility]

## Testing Recommendations

### Unit Tests
- [ ] L2 sequencer grace period enforcement
- [ ] Interest freeze during pause
- [ ] Synchronized pause state verification
- [ ] Pre-liquidation fee accrual
- [ ] PNL credit during liquidation
- [ ] Health improvement verification

### Integration Tests
- [ ] Sequencer restart liquidation wave simulation
- [ ] Pause/unpause state transitions
- [ ] Multi-collateral liquidation priority
- [ ] Position transfer + repayment routing

### Scenario Tests
- [ ] Mass liquidation after 24h sequencer downtime
- [ ] Interest accumulation over 7-day pause
- [ ] Cherry-picking attack on multi-collateral position

## Appendix

### L2 Sequencer Integration
[Chainlink sequencer uptime feed addresses and integration details]

### Historical Downtime Analysis
[Reference to L2 sequencer downtime incidents]

### LTV Comparison
[Comparison with other lending protocols' LTV gaps]

