Flash Loan Arbitrage: Zero-Capital DeFi Profits Explained
Flash loans let you borrow millions of dollars in crypto with no collateral โ and repay it in the same transaction. This guide explains how flash loan arbitrage works and how to build one.
Builder of AI agents, crypto trading bots, and open-source automation tools. Sharing practical guides on how to build, deploy, and profit from AI and DeFi technology.
What Is a Flash Loan?
A flash loan is a collateral-free loan that must be borrowed and repaid within a single blockchain transaction.
This is only possible because of how blockchains work: if you can't repay the loan within the same transaction, the entire transaction is reverted as if it never happened. There's zero risk to the lender.
The logic:
- Borrow $1,000,000 USDC from Aave
- Use it to execute an arbitrage
- Repay $1,000,000 + fee ($900 = 0.09%)
- Keep the profit
All of this happens in one transaction โ one block confirmation.
Why Flash Loans Matter
Flash loans democratize arbitrage. Before flash loans, to profit from a $500K arbitrage opportunity you needed $500K. Now you need:
- Knowledge to build the smart contract
- A few dollars in gas fees
- An opportunity to exploit
This is one of the most level playing fields in finance.
How Flash Loan Arbitrage Works
Transaction begins:
โ
โโ 1. Borrow 1,000,000 USDC from Aave (fee: 900 USDC)
โ
โโ 2. Buy ETH on Uniswap at $3,000 โ receive 333.33 ETH
โ
โโ 3. Sell ETH on Curve at $3,015 โ receive 1,004,995 USDC
โ
โโ 4. Repay Aave: 1,000,900 USDC
โ
โโ Profit: 4,095 USDC kept in your wallet
Transaction ends โ all settled in ~12 seconds.
Building a Flash Loan Contract (Aave V3)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import { FlashLoanSimpleReceiverBase } from "@aave/core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol";
import { IPoolAddressesProvider } from "@aave/core-v3/contracts/interfaces/IPoolAddressesProvider.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IUniswapV2Router {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
contract FlashLoanArbitrage is FlashLoanSimpleReceiverBase {
address public owner;
IUniswapV2Router constant uniswap = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
IUniswapV2Router constant sushiswap = IUniswapV2Router(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
constructor(address _addressProvider)
FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_addressProvider))
{
owner = msg.sender;
}
/**
* Called by Aave after sending us the borrowed funds.
* We must repay amountOwed before this function returns.
*/
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns (bool) {
// Decode our arbitrage parameters
(address tokenA, address tokenB, uint256 minProfit) = abi.decode(
params, (address, address, uint256)
);
// Step 1: Buy tokenB with tokenA on Uniswap
IERC20(asset).approve(address(uniswap), amount);
address[] memory path1 = new address[](2);
path1[0] = asset;
path1[1] = tokenB;
uint256[] memory amounts1 = uniswap.swapExactTokensForTokens(
amount, 0, path1, address(this), block.timestamp + 300
);
uint256 tokenBReceived = amounts1[amounts1.length - 1];
// Step 2: Sell tokenB back to tokenA on Sushiswap (higher price)
IERC20(tokenB).approve(address(sushiswap), tokenBReceived);
address[] memory path2 = new address[](2);
path2[0] = tokenB;
path2[1] = asset;
uint256[] memory amounts2 = sushiswap.swapExactTokensForTokens(
tokenBReceived, 0, path2, address(this), block.timestamp + 300
);
uint256 finalAmount = amounts2[amounts2.length - 1];
// Step 3: Verify profit and repay
uint256 amountOwed = amount + premium;
require(finalAmount >= amountOwed + minProfit, "Insufficient profit");
// Approve repayment
IERC20(asset).approve(address(POOL), amountOwed);
// Transfer profit to owner
IERC20(asset).transfer(owner, finalAmount - amountOwed);
return true;
}
/**
* Initiate the flash loan arbitrage
*/
function executeArbitrage(
address asset,
uint256 amount,
address tokenA,
address tokenB,
uint256 minProfit
) external {
require(msg.sender == owner, "Not owner");
bytes memory params = abi.encode(tokenA, tokenB, minProfit);
POOL.flashLoanSimple(
address(this), // receiver
asset, // asset to borrow
amount, // amount
params, // our encoded params
0 // referral code
);
}
}
Finding Flash Loan Opportunities
The hard part isn't the code โ it's finding profitable opportunities before others do.
import { ethers } from 'ethers'
async function findFlashLoanOpportunity(tokenA: string, tokenB: string, amount: bigint) {
// Get price on Uniswap
const uniswapPrice = await getUniswapPrice(tokenA, tokenB, amount)
// Get price on Sushiswap
const sushiPrice = await getSushiswapPrice(tokenA, tokenB, amount)
// Get price on Curve
const curvePrice = await getCurvePrice(tokenA, tokenB, amount)
const prices = [uniswapPrice, sushiPrice, curvePrice]
const maxPrice = prices.reduce((a, b) => a > b ? a : b)
const minPrice = prices.reduce((a, b) => a < b ? a : b)
const spreadPct = Number(maxPrice - minPrice) / Number(minPrice) * 100
const flashLoanFee = 0.09 // Aave fee
if (spreadPct > flashLoanFee + 0.1) { // Need > fee + 0.1% margin
return {
profitable: true,
buyExchange: prices.indexOf(minPrice),
sellExchange: prices.indexOf(maxPrice),
estimatedProfit: amount * BigInt(Math.floor((spreadPct - flashLoanFee) * 100)) / 10000n
}
}
return { profitable: false }
}
The MEV Reality
In practice, flash loan arbitrage is extremely competitive. MEV (Maximal Extractable Value) bots:
- Monitor the mempool for your transaction
- Copy it and pay higher gas to front-run you
- Or sandwich you to extract your profit
To compete, you need:
- Private RPC endpoints โ Submit through Flashbots to avoid mempool exposure
- Gas optimization โ Minimize gas to maximize profit window
- Speed โ Identify opportunities faster than competitors
Who Can Still Profit?
Flash loan arbitrage at scale is dominated by MEV specialists. But opportunities still exist for:
- Less-watched DEXs โ Newer or smaller chains with less bot competition
- Complex multi-hop routes โ More complexity = fewer bots that find it
- Cross-chain โ Bridges create arbitrage opportunities that single-chain bots miss
- Novel protocols โ New DeFi protocols often have mispricings for weeks
Practical Resources
- Aave Flash Loan Docs: docs.aave.com
- Flashbots (MEV protection): flashbots.net
- Tenderly (simulate transactions before sending): tenderly.co
- Our DeFi bot template includes flash loan scaffold code
Flash loan arbitrage is genuinely one of the most intellectually interesting areas of DeFi development. Even if not immediately profitable, the skills you build are immensely valuable.