Zero-collateral
atomic borrowing.

Borrow any amount from the pool with no collateral. Execute your strategy. Repay in the same block. If you don't repay — the transaction never happened.

Fee

0.09%

Repay window

1 tx

Collateral

None

Risk to pool

Zero

WETH

0.09% fee

Live on Sepolia

USDC

0.09% fee

Live on Sepolia

LINK

0.09% fee

Live on Sepolia
01

Call flashLoan()

You call pool.flashLoan(receiver, asset, amount). Zero collateral. No credit check.

02

Tokens arrive

Pool transfers the exact `amount` to your receiver contract before any checks.

03

executeOperation()

Your code runs. Arbitrage, liquidate, refinance, collateral swap — anything.

04

You TRANSFER back

You must TRANSFER (not approve) amount + fee back to pool before returning true.

05

Balance check

Pool verifies balanceOf(self) ≥ original + fee. If not — entire tx reverts. No risk.

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

import {IFlashLoanReceiver} from "./interfaces/IFlashLoanReceiver.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title  ArbitrageReceiver
 * @notice Borrow USDC → buy WETH on DEX A → sell on DEX B → repay + profit
 */
contract ArbitrageReceiver is IFlashLoanReceiver {
    address public immutable pool;

    function executeOperation(
        address asset,   // USDC
        uint256 amount,  // borrowed amount
        uint256 fee,     // 0.09% of amount
        address,
        bytes calldata
    ) external override returns (bool) {
        // 1. Your strategy runs here — e.g. buy low, sell high
        uint256 wethBought   = _buyOnDexA(asset, amount);
        uint256 usdcReceived = _sellOnDexB(wethBought);

        // 2. TRANSFER back (not approve) — pool checks balanceOf
        require(usdcReceived >= amount + fee, "not profitable");
        IERC20(asset).transfer(pool, amount + fee);
        // profit stays in this contract

        return true;
    }

    function runArbitrage(uint256 borrowAmt) external {
        ILendingPool(pool).flashLoan(
            address(this), USDC, borrowAmt, ""
        );
    }
}

TRANSFER, not approve

Pool reads balanceOf(self) after your call. You must push tokens back — pool never calls transferFrom.

Single transaction

Borrow + strategy + repayment all happen atomically. A failed repayment reverts everything instantly.

Fee to depositors

The 0.09% fee bumps the liquidity index, distributing yield proportionally to all lToken holders.