defi/amm-lending-patterns

AMM & Lending Protocol Design Patterns

ethereumdefi-guide👥 Communityconfidence highhealth 100%
v1.0.0·Updated 3/26/2026

Distilled from DeFiLlama data covering the top AMM protocols ($8.7B TVL combined: Uniswap V3 $1.71B, Curve $1.85B, PancakeSwap $1.67B, Raydium $1.05B) and lending protocols ($42.9B TVL combined: Aave V3 $23.9B, Morpho $6.7B, Sky/MakerDAO $7.3B, Compound $1.3B).


AMM Design Patterns

1. Constant Product Formula (x·y = k)

The foundational AMM invariant, introduced by Uniswap V1/V2:

x * y = k

Where x and y are reserve amounts of token A and B. The spot price is x/y. Every swap moves along the curve, maintaining k.

Key properties:

  • Price impact grows non-linearly with trade size
  • Price slippage formula: output = (y * amountIn) / (x + amountIn)
  • 0.3% fee adds: amountInWithFee = amountIn * 997 / 1000

Implementation pattern (Uniswap V2 style):

function swap(uint amount0Out, uint amount1Out, ...) external {
    uint balance0 = IERC20(token0).balanceOf(address(this)) - amount0Out;
    uint balance1 = IERC20(token1).balanceOf(address(this)) - amount1Out;
    require(balance0 * balance1 >= uint(reserve0) * reserve1, "K"); // invariant check
}

Pitfall: K-invariant check alone doesn't prevent flash loan exploitation — must check K after the callback resolves.

2. Concentrated Liquidity (Uniswap V3)

Uniswap V3 allows LPs to provide liquidity within a custom price range [P_lower, P_upper]. This achieves up to 4000× more capital efficiency for stable pairs but requires active management.

Key formulas:

liquidity L = sqrt(x * y)
x = L * (sqrt(P_upper) - sqrt(P)) / (sqrt(P) * sqrt(P_upper))
y = L * (sqrt(P) - sqrt(P_lower))

Design implications:

  • Single-sided liquidity: if price moves outside range, LP holds 100% of the out-of-range token
  • Fee tiers: 0.01% (stable pairs), 0.05% (major pairs), 0.30% (standard), 1.00% (exotic)
  • Tick spacing: lower fee tiers have finer tick granularity

Implementation pitfalls:

  • Out-of-range positions earn no fees — active management required
  • Tick math requires careful rounding (round against LP to prevent K violations)
  • sqrtPriceX96 fixed-point format introduces precision constraints

3. StableSwap / Curve Formula

For assets that should trade near 1:1 (e.g., USDC/USDT, stETH/ETH), the StableSwap invariant:

A * n^n * sum(x_i) + D = A * D * n^n + D^(n+1) / (n^n * prod(x_i))

Where A is the amplification coefficient controlling how "flat" the curve is near equilibrium.

Design implications:

  • Higher A → less price slippage near peg, more divergence when depeg occurs
  • A should be governed carefully — sudden changes break arbitrage assumptions
  • Used by all major stablecoin pools, LSD pools (stETH/ETH), and cross-chain bridges

4. AMM Fee Calculation & LP Token Math

LP token minting (Uniswap V2 first deposit):

liquidity = sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;

Subsequent deposits (proportional):

liquidity = min(amount0 * totalSupply / reserve0, amount1 * totalSupply / reserve1);

Critical pitfall: If an attacker donates tokens to the pool before the first LP deposits, they can inflate the price and manipulate the sqrt(amount0 * amount1) calculation for the first LP. Fix: enforce MINIMUM_LIQUIDITY = 1000 permanently burned to lock the initial ratio.

5. Impermanent Loss (IL)

IL is the loss LPs experience vs holding when prices diverge:

IL = 2 * sqrt(price_ratio) / (1 + price_ratio) - 1
Price changeIL
2× (or 0.5×)5.7%
5× (or 0.2×)25.5%
10× (or 0.1×)42.5%

For protocol designers: IL protection mechanisms (IL insurance, single-sided staking) attempt to compensate LPs but introduce significant protocol risk if miscalibrated.


Lending Protocol Design Patterns

6. Utilization-Based Interest Rate Curves

The standard lending interest rate model (Compound/Aave):

if utilization <= kink:
    borrowRate = baseRate + (utilization / kink) * slopeBeforeKink
else:
    borrowRate = baseRate + slopeBeforeKink + ((utilization - kink) / (1 - kink)) * slopeAfterKink

Typical parameters (Aave USDC):

  • Base rate: 0%
  • Kink: 80% utilization
  • Slope before kink: 4% APR
  • Slope after kink: 75% APR (aggressive — incentivizes repayments)

Why the kink matters: At 80% utilization, the rate jumps sharply. This protects depositors from bank runs — if too many users borrow, rates become punitive, incentivizing repayment before the pool empties.

7. Health Factor & Liquidation Mechanics

Health Factor:

HF = sum(collateral_i * liquidationThreshold_i) / totalDebt

When HF < 1, the position is liquidatable.

Liquidation process (Aave-style):

  1. Liquidator calls liquidationCall(collateralAsset, debtAsset, user, debtToCover)
  2. Liquidator repays debtToCover on behalf of user
  3. Liquidator receives debtToCover * liquidationBonus in collateral
  4. Typical liquidation bonus: 5–15% depending on collateral risk tier

Implementation pitfall — liquidation cascade: When collateral prices drop sharply, many positions become liquidatable simultaneously. Mass liquidations create selling pressure on the collateral asset, which drops prices further. Aave mitigates this via:

  • Gradual liquidation (cap on single liquidation amount)
  • Supply caps per asset
  • Risk-tiered isolation mode for high-volatility assets

8. Flash Loans

Flash loans are uncollateralized loans that must be repaid within the same transaction:

function flashLoan(address receiver, address asset, uint256 amount, bytes calldata params) external {
    uint256 balanceBefore = IERC20(asset).balanceOf(address(this));
    IERC20(asset).transfer(receiver, amount);
    IFlashLoanReceiver(receiver).executeOperation(asset, amount, fee, params);
    require(IERC20(asset).balanceOf(address(this)) >= balanceBefore + fee, "not repaid");
}

Legitimate use cases: Arbitrage, self-liquidation, collateral swaps, one-tx leverage entry/exit.

Attack surface: Flash loans amplify every oracle manipulation and reentrancy attack. Never use spot prices from the same block as a flash loan for any financial decision.

9. Reserve Factor & Protocol Revenue

Lending protocols extract fees by taking a cut of interest payments:

supplierAPY = borrowAPY * utilizationRate * (1 - reserveFactor)
protocolRevenue = totalInterestPaid * reserveFactor

Typical reserve factors: 5–25%. Higher reserve factors reduce depositor APY and make the protocol less competitive.

10. ERC-4626 Tokenized Vault Standard

Modern lending implementations use ERC-4626 to standardize vault interfaces:

function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
function convertToShares(uint256 assets) external view returns (uint256);
function convertToAssets(uint256 shares) external view returns (uint256);

Critical invariant: convertToAssets(convertToShares(x)) <= x. If not maintained, vault is exploitable.

Common pitfall: Inflation attack on first deposit (same as AMM). Mitigation: virtual shares/assets offset (totalAssets + 1 / totalSupply + 1).


Composability Patterns & Risks

Flash Loan + AMM + Lending Interaction

The typical DeFi "Lego" attack pattern:

  1. Flash loan 1M USDC
  2. Deposit USDC as collateral in lending protocol
  3. Borrow asset X against it
  4. Sell X on AMM to manipulate price
  5. Exploit the manipulated price
  6. Repay flash loan

Defense: Protocols should use time-weighted prices, not spot prices, for any action that can follow a flash loan in the same block.

Design Checklist

  • AMM: Is the K-invariant checked after the full callback resolves?
  • AMM V3: Is tick rounding direction correct (round against LP)?
  • AMM first deposit: Is MINIMUM_LIQUIDITY enforced to prevent donation attacks?
  • Lending: Does the interest rate curve have a kink to protect against bank runs?
  • Lending: Are liquidations capped per transaction to prevent cascades?
  • Flash loans: Does any price oracle read in the same block become exploitable?
  • ERC-4626: Is the convertToShares/convertToAssets round-trip safe against inflation attacks?