lending-protocol-patterns

star 47

Auto-loaded by defi-auditor agent during Phase 2 when analyzing lending protocols. Provides patterns for: liquidation logic, interest rate models, collateral management, health factor calculations, bad debt handling. Core vulnerabilities: self-liquidation, precision loss, oracle manipulation, collateral factor attacks.

PurpleAILAB By PurpleAILAB schedule Updated 1/26/2026

name: Lending Protocol Patterns description: > Auto-loaded by defi-auditor agent during Phase 2 when analyzing lending protocols. Provides patterns for: liquidation logic, interest rate models, collateral management, health factor calculations, bad debt handling. Core vulnerabilities: self-liquidation, precision loss, oracle manipulation, collateral factor attacks. user-invocable: false

Lending Protocol Patterns

This skill provides comprehensive knowledge for auditing DeFi lending protocols.

Core Lending Concepts

Concept Description
Collateral Factor Max borrow % against collateral
Liquidation Threshold Health level triggering liquidation
Utilization Rate Borrowed / Total Supplied
Interest Rate Function of utilization
Health Factor Collateral value / Debt value

Liquidation Vulnerabilities

1. Profitable Self-Liquidation

Vulnerable Pattern:

// DANGEROUS: Liquidator bonus too high
uint256 constant LIQUIDATION_BONUS = 15e16; // 15%

function liquidate(address user, uint256 repayAmount) external {
    // Attacker can:
    // 1. Borrow at 80% LTV
    // 2. Wait for tiny price drop
    // 3. Self-liquidate with 15% bonus
    // = Free 15% - (100% - 80%) = Net profit!
}

Check: Liquidation bonus should be less than (100% - Max LTV).

2. Liquidation Cascade

// When one liquidation triggers another
// Large position liquidated → price drops → more liquidations

// Mitigations:
// - Gradual liquidation (partial)
// - Circuit breakers
// - Liquidation delays

3. Bad Debt Accumulation

Vulnerable Pattern:

// DANGEROUS: No bad debt handling
function liquidate(address user) external {
    // If collateral < debt after liquidation
    // Bad debt remains in protocol
    // Eventually becomes insolvent
}

// SECURE: Handle underwater positions
function liquidate(address user) external {
    uint256 collateralValue = getCollateralValue(user);
    uint256 debtValue = getDebtValue(user);

    if (collateralValue < debtValue) {
        // Socialize bad debt or use insurance fund
        uint256 badDebt = debtValue - collateralValue;
        insuranceFund -= min(badDebt, insuranceFund);
    }
}

Interest Rate Model

Standard Jump Rate Model

contract JumpRateModel {
    uint256 public baseRate;      // Rate at 0% utilization
    uint256 public multiplier;    // Rate increase per utilization
    uint256 public jumpMultiplier; // Rate increase above kink
    uint256 public kink;          // Utilization % where jump occurs

    function getBorrowRate(uint256 cash, uint256 borrows)
        public view returns (uint256)
    {
        uint256 utilization = borrows * 1e18 / (cash + borrows);

        if (utilization <= kink) {
            return baseRate + utilization * multiplier / 1e18;
        } else {
            uint256 normalRate = baseRate + kink * multiplier / 1e18;
            uint256 excessUtil = utilization - kink;
            return normalRate + excessUtil * jumpMultiplier / 1e18;
        }
    }
}

Interest Rate Vulnerabilities

1. Rate Manipulation

// Attacker can manipulate utilization
// 1. Flash loan large amount
// 2. Deposit → lower utilization → lower rates
// 3. Borrow at low rate
// 4. Withdraw and repay flash loan

2. Precision Loss

// DANGEROUS: Interest rounds to 0 for small amounts
uint256 interest = principal * rate / SECONDS_PER_YEAR;
// If principal * rate < SECONDS_PER_YEAR, interest = 0

// SOLUTION: Accumulate interest with high precision
uint256 interestAccumulator; // Ray (1e27) precision

Collateral Vulnerabilities

1. Collateral Factor Changes

// DANGEROUS: Instant collateral factor reduction
function setCollateralFactor(address token, uint256 newFactor) external {
    collateralFactors[token] = newFactor;
    // Existing borrowers may become instantly liquidatable!
}

// SECURE: Grace period or gradual reduction
function setCollateralFactor(address token, uint256 newFactor) external {
    require(newFactor >= collateralFactors[token] - MAX_DECREASE);
    pendingFactors[token] = newFactor;
    factorEffectiveTime[token] = block.timestamp + TIMELOCK;
}

2. Collateral Oracle Manipulation

// Collateral valued using manipulable oracle
// Attacker inflates collateral value → borrows more → profits
// See oracle vulnerability patterns

3. Toxic Collateral

// Collateral that can't be liquidated:
// - Pausable tokens
// - Blacklistable tokens
// - Low liquidity tokens

// Mitigation: Whitelist collateral carefully

Borrowing Vulnerabilities

1. Borrow Cap Bypass

// VULNERABLE: Cap checked only on new borrows
function borrow(uint256 amount) external {
    require(totalBorrowed + amount <= borrowCap);
    // Interest accrual can push over cap!
}

// Check on any state-changing operation

2. Same-Block Borrow-Repay

// EXPLOIT: Borrow and repay in same block
// No interest accrued = free leverage

function borrow(uint256 amount) external {
    require(lastBorrowBlock[msg.sender] < block.number);
    lastBorrowBlock[msg.sender] = block.number;
    // ...
}

Health Factor Calculations

Standard Formula

Health Factor = (Collateral Value × LTV) / Debt Value

Health Factor > 1: Safe
Health Factor < 1: Liquidatable

Vulnerabilities

1. Stale Health Factor

// DANGEROUS: Cached health factor
mapping(address => uint256) public healthFactors;

// Health factors become stale as prices change
// Always compute in real-time

2. Rounding Direction

// SECURE: Round health factor DOWN (safer)
uint256 healthFactor = collateralValue * 1e18 / debtValue;

// Round debt UP when calculating
uint256 debt = (borrowed * (1e18 + interest) + 1e18 - 1) / 1e18;

Common AAVE/Compound Patterns

Reserve Factor

// Protocol takes cut of interest
uint256 interestToProtocol = interest * reserveFactor / 1e18;
uint256 interestToSuppliers = interest - interestToProtocol;

Supply Index

// Track earnings per token
// supplyIndex increases as interest accrues
uint256 newIndex = oldIndex + (interest * 1e18 / totalSupply);

// User earnings = balance * (currentIndex - userIndex) / 1e18

Lending Audit Checklist

Liquidation

  • Liquidation bonus < (100% - max LTV)
  • Bad debt handling exists
  • Partial liquidation supported
  • Liquidation can't be blocked (pausable tokens)
  • Self-liquidation not profitable

Interest

  • Interest accrues correctly over time
  • No precision loss on small amounts
  • Rate manipulation resistance
  • Compound interest handled

Collateral

  • Oracle is manipulation-resistant
  • Collateral factor changes have timelock
  • Collateral whitelist is reasonable
  • Handles rebasing/weird tokens properly

Health Factor

  • Computed in real-time
  • Rounding favors protocol safety
  • Handles all edge cases (0 debt, 0 collateral)

Access Control

  • Only authorized can change parameters
  • Emergency pause exists
  • Parameter bounds enforced

Severity Classification

Critical

  • Self-liquidation profitable
  • Bad debt not handled
  • Oracle manipulation allows draining

High

  • Interest precision loss
  • Collateral factor instant changes
  • Same-block manipulation

Medium

  • Missing borrow caps
  • Liquidation can be blocked
  • Rate model edge cases
Install via CLI
npx skills add https://github.com/PurpleAILAB/Vigilo --skill lending-protocol-patterns
Repository Details
star Stars 47
call_split Forks 13
navigation Branch main
article Path SKILL.md
More from Creator