← Protocols
ERC-3156 — Flash Loans
Standard / EIP·EVM

ERC-3156 — Flash Loans

01Description

Final ERC defining a unified single-asset flash-loan interface: `IERC3156FlashLender` (lender) and `IERC3156FlashBorrower` (borrower callback). Standardizes how protocols expose uncollateralized one-transaction loans so arbitrageurs, liquidators, and refinancers can interoperate across lenders.

02Best for
  • 01flash-loan-powered arbitrage
  • 02atomic liquidations
  • 03collateral-swap / debt-refinance flows
  • 04cross-protocol composability
  • 05lender-side flash-loan exposure
03Install
  • pnpm add @openzeppelin/contracts
  • forge install vectorized/solady
  • forge install aave/aave-v3-core
05Prompt snippet
Lenders implement `IERC3156FlashLender` with `maxFlashLoan(address token) view returns (uint256)`, `flashFee(address token, uint256 amount) view returns (uint256)`, and `flashLoan(IERC3156FlashBorrower receiver, address token, uint256 amount, bytes data) returns (bool)`. Borrowers implement `IERC3156FlashBorrower.onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes data) returns (bytes32)` and MUST return `keccak256('ERC3156FlashBorrower.onFlashLoan')` and approve the lender for `amount + fee` before returning. The lender pulls repayment via `transferFrom` after the callback. Use OpenZeppelin's `ERC20FlashMint` for ERC-20-mint-style flash loans or Aave V3's `flashLoanSimple` (3156-compatible) for pool-based loans. Always validate `msg.sender == trustedLender` and `initiator == address(this)` inside `onFlashLoan` to block arbitrary callers.
06Gotchas
  • Callback abuse: a malicious lender (or a spoofed call from any contract) can invoke your `onFlashLoan` directly — always check `require(msg.sender == trustedLender)` and `require(initiator == address(this) || initiator == trustedCaller)` first; missing these is the #1 flash-loan-borrower exploit.
  • Return-value mismatch: the borrower MUST return the magic hash `keccak256('ERC3156FlashBorrower.onFlashLoan')` — returning `bytes32(0)` or `true` looks fine in tests but reverts on real lenders that check the magic value.
  • Repayment uses `transferFrom`, not `transfer` — the borrower must `approve(lender, amount + fee)` inside the callback; forgetting the approval reverts after all your arbitrage logic ran.
  • Reentrancy: flash loans turn every state-changing function into a potential reentrancy vector; combine `nonReentrant` modifiers with read-only-reentrancy guards on view functions used as oracles (Curve LP price, AMM TWAP).
  • Fee-on-transfer / rebasing tokens silently break the standard — `amount + fee` is not what arrives at the lender; either reject these tokens explicitly or compute repayment from balance deltas.
  • Flash-loan price-oracle manipulation: never read AMM spot prices in the same tx — flash loans are routinely used to bend Uniswap V2 prices and drain anything that quotes from `getReserves`; require multi-block TWAPs or Chainlink feeds.
07Alternatives