Sign in

Flash loans

A flash loan lets a contract borrow any amount of any token without putting up collateral, on the condition that the loan is repaid before the same transaction ends. If the borrower doesn't repay, the entire transaction reverts and the loan effectively never happened.

The trick: atomicity replaces collateral

In normal lending, a borrower posts collateral worth more than the loan. The lender accepts default risk in exchange for keeping that collateral if the borrower disappears. Flash loans don't work that way. The borrower posts nothing.

The reason it's safe for the lender is that Ethereum transactions are atomic. Every state change inside one transaction either commits together or reverts together. There's no partial outcome. So the lender's logic is: send the borrower the funds, give them control to do whatever they want, then at the end of the call check the balance is back. If the balance hasn't returned (plus a small fee), the lender simply reverts the transaction. The funds were never really sent. The borrower never really had them.

For the lender this is risk-free. The worst case is the transaction reverts and they earn no fee. They never lose principal, because principal that doesn't come back means the transaction unwinds and the principal is still in their pool.

Flash loan: borrow without collateral, repay before the transaction ends, or revert Borrower contract your code Flash loan provider Aave / Balancer / Uniswap — inside ONE transaction — 1. flashLoan(amount, params) 2. transfer N tokens to borrower 3. call executeOperation() on borrower 4. do anything swap, arb, liquidate, refinance, attack, whatever fits in one tx 5. return N + fee to provider 6. check balance balance >= amount + fee? if no → revert entire tx If repaid: tx succeeds, profit kept If not repaid: entire tx reverts, loan never existed

This is the only kind of loan that can exist this way. Off-chain finance has no equivalent because there's no other system where a multi-step transaction can be reversed cleanly if the last step fails. On Ethereum, that's just how transactions work.

The borrower's side

A contract that wants to take a flash loan implements a callback function (the exact name depends on the provider; Aave calls it executeOperation, Balancer calls it receiveFlashLoan, Uniswap V3 uses uniswapV3FlashCallback). The contract requests a loan, the provider sends the tokens and immediately calls back into the contract, and the contract has the duration of that callback to do whatever it wants. Before the callback returns, the contract must have approved (or pushed) enough tokens back to the provider to cover the loan plus the fee.

A minimal sketch in Solidity:

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

interface IFlashLoanProvider {
    function flashLoan(address borrower, address token, uint256 amount, bytes calldata data) external;
}

interface IFlashLoanReceiver {
    function executeOperation(address token, uint256 amount, uint256 fee, bytes calldata data) external;
}

contract MyArbitrageur is IFlashLoanReceiver {
    IFlashLoanProvider public provider;

    function startArbitrage(address token, uint256 amount) external {
        provider.flashLoan(address(this), token, amount, "");
        // by the time this returns, the entire arb has executed
    }

    function executeOperation(address token, uint256 amount, uint256 fee, bytes calldata) external {
        // 1. we now hold `amount` of token
        // 2. do whatever the strategy needs (swaps, calls to other protocols)
        // 3. approve the provider to pull amount + fee back
        IERC20(token).approve(msg.sender, amount + fee);
    }
}

Fees are small. Aave charges 0.05% of the borrowed amount at the time of writing. Balancer charges nothing on its core flash loans, which is one reason it's a popular source. Uniswap V3's flash mechanism charges the regular pool swap fee.

There's no practical cap on the borrowable amount beyond the provider's pool depth. If Aave has $400M of USDC in its lending pool, that's the limit. Most flash loans are far smaller than this, but the upper end gets large.

What legitimate users do with them

Flash loans look like a tool for attackers when you first encounter them, but the dominant volume across the major providers is legitimate. Three main categories.

Arbitrage between exchanges. If Uniswap and SushiSwap show different prices for the same pair, someone can profit by buying on the cheaper one and selling on the more expensive one. Without a flash loan they'd need the upfront capital. With a flash loan they can do it from a contract that holds nothing.

Legitimate use: cross-DEX arbitrage with zero starting capital Setup (one block): Uniswap pool prices ETH at $3,000 | SushiSwap pool prices ETH at $3,050 A $50 spread between two DEXes. Whoever closes it captures the spread. Arbitrageur's transaction (no upfront capital needed): 1. Flash-loan 1,000,000 USDC from Aave cost: small fee (e.g. 0.05% = $500) 2. Buy ETH on Uniswap with the 1M USDC receives ~333.33 ETH at $3,000 3. Sell that ETH on SushiSwap for USDC receives ~1,016,666 USDC at $3,050 4. Repay flash loan: 1,000,500 USDC leaves ~16,166 USDC remaining Net profit: ~16,166 USDC (minus gas) Arbitrageur started with zero capital, ended with $16k. If anything failed mid-way (insufficient liquidity, slippage too high), the whole tx reverts. Effect on the two pools: Uniswap (sold to): ETH price moved UP slightly, e.g. from $3,000 to $3,015 SushiSwap (bought from): ETH price moved DOWN, e.g. from $3,050 to $3,035

Arbitrage is one of the things that keeps prices consistent across DEXes. Without arbitrageurs, every pool would drift independently and traders would face wildly different prices on different venues. The flash loan removes the capital barrier to doing this work, which makes the price-stabilizing pressure stronger.

Refinancing and collateral swaps. A user has a loan on Aave collateralized by ETH. They want to switch to using staked-ETH as collateral instead. Without a flash loan, they'd have to repay the loan first (which means they need the USDC they don't have), withdraw the ETH, swap to staked-ETH, redeposit, and reborrow. With a flash loan they can do all of it in a single transaction: flash-loan the USDC to repay, withdraw ETH, swap to staked-ETH, redeposit, reborrow, repay the flash loan from the new borrow.

Liquidations. When someone else's loan goes underwater, anyone can liquidate it and take a bounty. Liquidators normally need capital sitting around to repay the bad loan. With a flash loan, they can liquidate any size position with no balance sheet, capturing the bounty cleanly.

In each of these, the flash loan is doing useful work. Capital efficiency goes up because nobody has to keep idle inventory waiting for opportunities.

The dark side: oracle manipulation

The flash loan stops being neutral the moment it's used to manipulate something the rest of the system depends on. The most common target is a price oracle that reads from a single AMM pool.

Recall how V2 pricing works. The pool's spot price is just the ratio of its reserves. Any swap moves the ratio. A big-enough swap moves it a lot. Normally this isn't an issue because moving the price means paying a lot of slippage, and any attacker would lose more in slippage than they could gain by exploiting the moved price. But if some other protocol reads that pool's spot price and trusts it as "the price of TOKEN," an attacker who can briefly distort the pool's reserves can extract value from the downstream protocol.

The flash loan provides exactly the capital needed for the distortion, free of charge.

The attack: a flash loan turns a thin pool into a fake oracle reading Setup: TOKEN/USDC pool: 100,000 TOKEN + 1,000,000 USDC → spot price = $10/TOKEN Lending protocol: reads TOKEN price from this pool, accepts TOKEN as collateral at 80% LTV Attacker holds nothing. They need to extract money from the lending protocol. 1. Flash-loan 1,000,000 USDC from Aave attacker now holds 1M USDC, owes 1M USDC + fee to Aave 2. Dump the 1M USDC into the TOKEN/USDC pool, buying TOKEN pool after: 50,000 TOKEN + 2,000,000 USDC new spot price = $40/TOKEN ← inflated 4x. Attacker now holds 50,000 TOKEN. 3. Lending protocol reads the pool. Sees TOKEN at $40. Attacker deposits 50,000 TOKEN as collateral. Protocol values it at $2,000,000. Attacker borrows 1,600,000 USDC against this "collateral" (80% LTV). 4. Repay flash loan: 1,000,500 USDC back to Aave attacker has 599,500 USDC left in hand, with debt to the lending protocol After the transaction ends: Arbitrageurs reverse the pool manipulation, TOKEN returns to $10. Attacker's 50,000 TOKEN collateral is now worth only $500,000, not $2,000,000. Final accounting (attacker walks away from the bad loan): Attacker Walked off with: $599,500 Lost as collateral: $500k TOKEN Net: profit ~$600k from 0 capital Lending protocol Lent out: $1,600,000 Got back: $500k collateral Net: lost ~$1.1M to bad debt The protocol's mistake: trusting a spot price that one flash-loaned trade could move.

The numbers in the diagram are illustrative. The pattern is the same: borrow huge -> distort some pool -> exploit a downstream protocol that trusted the pool's spot price -> repay -> walk away with the difference.

Why doesn't the manipulation cost the attacker more than they gain? Two reasons.

The pool manipulation is temporary. The attacker swaps in, exploits, and then either reverses the swap, recovering most of what they "paid", or just lets arbitrageurs do the reversal a few blocks later. The net cost of the manipulation is mostly pool slippage and fees, not the full nominal amount they pushed through.

The exploit is leveraged. A 4x price distortion can let the attacker over-borrow far more than the slippage cost of creating that distortion, especially when LTV ratios on the downstream protocol allow large borrows against the inflated collateral. Even after slippage, the math comes out positive.

The historical version of this attack class hit bZx in February 2020, twice in one week, for combined losses around $1M. It hit Harvest Finance later that year for $24M. It hit Cream Finance, Warp Finance, and many others. In total, oracle manipulation enabled by flash loans has cost protocols hundreds of millions of dollars, and the pattern still surfaces on smaller projects with weak oracle designs.

Why this is a flash loan problem, sort of

The attacker doesn't strictly need a flash loan to manipulate a pool. Anyone with enough capital can do the same attack by simply holding the tokens. The flash loan just lowers the bar from "needs $10M of inventory" to "needs gas plus a flash-loan fee." It democratized this class of attack.

The deeper issue is that a spot price from a single AMM pool was never a safe oracle. It was always manipulable, just expensively. Flash loans exposed how cheap the manipulation actually is.

So the defense isn't "block flash loans". The defense is at the oracle layer. Protocols need price signals that can't be moved by a single transaction.

Three main approaches in production today:

External oracles like Chainlink. The price is set by off-chain aggregation across many exchanges. A single on-chain swap can't move it. This is the dominant defense.

Time-weighted prices, where the oracle reports an average over a window rather than a spot read. A one-block manipulation contributes only one block's worth of price to the average, which dilutes its impact to near zero. The next lecture covers this in detail.

Multi-source checks, where the protocol consumes two oracles and reverts if they diverge significantly. This catches the case where one of them is wrong or being attacked.

The next lecture covers TWAP oracles, which are the main on-chain answer to this problem when an external oracle isn't available or sufficient. Knowing the attack pattern you just walked through, the design choices TWAP makes will land more clearly.