DeFi Patterns

An automated market maker holds reserves x and y of two tokens and keeps x * y = k (ignoring fees).

37.1 Constant-product AMM (Uniswap v2 style)

An automated market maker holds reserves x and y of two tokens and keeps x * y = k (ignoring fees). Price = y / x. Liquidity providers deposit both tokens and receive LP shares.

Output amount for input dx with a 0.3% fee: dy = (dx * 997 * y) / (x * 1000 + dx * 997)

Evolution: Uniswap v3 (concentrated liquidity, ticks, NFT positions, TWAP oracle), Uniswap v4 (2025: singleton PoolManager, hooks, flash accounting with transient storage), Curve (StableSwap invariant for pegged assets), Balancer (weighted pools).

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract MiniAMM is ERC20, ReentrancyGuard {
    using SafeERC20 for IERC20;

    IERC20 public immutable token0;
    IERC20 public immutable token1;
    uint256 public reserve0;
    uint256 public reserve1;
    uint256 private constant MINIMUM_LIQUIDITY = 1000;

    error InsufficientOutput();
    error InsufficientLiquidity();
    error InvalidToken();
    error Expired();

    event Swap(address indexed user, address tokenIn, uint256 amountIn, uint256 amountOut);

    constructor(IERC20 _t0, IERC20 _t1) ERC20("MiniAMM LP", "MLP") {
        token0 = _t0;
        token1 = _t1;
    }

    function addLiquidity(uint256 amount0, uint256 amount1) external nonReentrant returns (uint256 shares) {
        token0.safeTransferFrom(msg.sender, address(this), amount0);
…

37.2 Staking rewards (Synthetix StakingRewards pattern)

Rewards are distributed per second proportionally to stake, using a cumulative "reward per token" accumulator — O(1) per user action, no loops.

(If the staking and reward token are the same, the balance check must subtract totalStaked.)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract StakingRewards is Ownable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    IERC20 public immutable stakingToken;
    IERC20 public immutable rewardToken;

    uint256 public rewardRate;              // reward tokens per second
    uint256 public periodFinish;
    uint256 public lastUpdate;
    uint256 public rewardPerTokenStored;    // scaled by 1e18
    uint256 public totalStaked;

    mapping(address => uint256) public staked;
    mapping(address => uint256) public userRewardPerTokenPaid;
    mapping(address => uint256) public rewards;

    constructor(IERC20 _stake, IERC20 _reward) Ownable(msg.sender) {
        stakingToken = _stake;
        rewardToken = _reward;
    }

    modifier updateReward(address account) {
        rewardPerTokenStored = rewardPerToken();
        lastUpdate = lastTimeRewardApplicab
…

37.3 Lending basics

Lending protocols (Aave, Compound, Morpho, Spark) let users supply assets to earn interest and borrow against collateral.

Collateral factor / LTV max borrow as a fraction of collateral value (e.g., 75%)

collateralValue * liquidationThreshold / debtValue; < 1 → liquidatable

borrows / (cash + borrows); drives the interest rate curve cumulative index (like reward-per-token) so interest accrues without loops third parties repay debt and seize collateral at a bonus prices from Chainlink etc. — the most critical dependency

// Core health check (simplified, 18-decimal USD values)
function _isHealthy(address user) internal view returns (bool) {
    uint256 collateralUsd = collateral[user] * oracle.price(collateralToken) / 1e18;
    uint256 debtUsd = debt[user] * oracle.price(debtToken) / 1e18;
    return debtUsd * 10_000 <= collateralUsd * LIQUIDATION_THRESHOLD_BPS;
}

37.4 Flash loans

A flash loan lends any amount with no collateral, provided it is repaid (plus fee) within the same transaction; otherwise everything reverts. Standard interface: ERC-3156.

Legitimate uses: arbitrage, liquidations, collateral swaps, refinancing. Flash loans also amplify attacks on contracts that trust spot prices or instant voting power — design assuming any user can have unlimited capital for one transaction.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

interface IFlashBorrower {
    function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes calldata data)
        external returns (bytes32);
}

contract FlashLender is ReentrancyGuard {
    using SafeERC20 for IERC20;
    bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
    uint256 public constant FEE_BPS = 9;   // 0.09%

    function flashLoan(IFlashBorrower receiver, address token, uint256 amount, bytes calldata data)
        external nonReentrant returns (bool)
    {
        uint256 balanceBefore = IERC20(token).balanceOf(address(this));
        uint256 fee = amount * FEE_BPS / 10_000;
        IERC20(token).safeTransfer(address(receiver), amount);
        require(
            receiver.onFlashLoan(msg.sender, token, amount, fee, data) == CALLBACK_SUCCESS,
            "callback failed"
        );
        IERC20(token).s
…

37.5 Other DeFi primitives

Stablecoins (collateralized like DAI/USDS, fiat-backed like USDC, synthetic like USDe), yield aggregators (ERC-4626 vaults), perpetual DEXs, options, liquid staking (stETH, rETH) and restaking, intents and solvers (UniswapX, CoW), cross-chain bridges.