---
eip: 7399
title: ⚡ Flash Loans ⚡
description: Interfaces and processes for flash loans
author: Alberto Cuesta Cañada (@alcueca), Michael Amadi (@AmadiMichaels), Devtooligan (@devtooligan), Ultrasecr.eth (@ultrasecreth), Sam Bacha (@sambacha)
discussions-to: https://ethereum-magicians.org/t/erc7400-flash-loans/15211
status: Review
type: Standards Track
category: ERC
created: 2023-07-25
requires: 20
---

## Abstract

A flash loan is a loan between lender and borrower smart contracts that must be repaid, plus an optional fee, before the end of the transaction. This ERC specifies interfaces for lenders to accept flash loan requests, and for borrowers to take temporary control of the transaction within the lender execution. The process for the safe execution of flash loans is also specified.

## Motivation

The current state of the flash loan ecosystem is fragmented and lacks standardization, leading to several challenges for both lenders and borrowers. The absence of a common interface results in increased integration efforts, as each flash loan provider implements its own unique approach. This lack of standardization is expected to become more problematic as the ecosystem grows, requiring more resources to maintain compatibility.

A comprehensive analysis of the existing flash loan protocols reveals significant differences in their implementations, including:

- Inconsistent syntax for initiating flash loans across different platforms.
- Variations in the relationship between the loan receiver and the callback receiver, with some protocols allowing different addresses for each role while others do not.
- Divergent repayment mechanisms, with some lenders pulling the principal and fee from the loan receiver and others requiring the loan receiver to manually return the funds.
- Disparities in the treatment of flash minting, where some lenders allow the creation of any amount of their native asset without charging a fee, effectively permitting flash loans bounded by computational constraints rather than asset ownership limitations.

To address these inconsistencies and promote a more efficient and accessible flash loan ecosystem, this ERC specifies a standardized interface that encompasses the maximum flexibility required by both lenders and borrowers. By consolidating the various approaches into a unified standard, this proposal aims to streamline the integration process, enabling borrowers to seamlessly switch between flash lenders without the need for code modifications.

## Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Under this standard a flash loan is a loan of an `amount` of an [ERC-20](./eip-20.md) `asset` from a `lender`. This loan can remain open for the span of a single `flash` call in the `lender`.

This `amount` plus a `fee` defined by the `lender` in the same `asset` must be repaid before the end of `flash` call at a _repayment receiver_ address defined by the `lender`.

The `flash` function is called by the `initiator`, who defines the _loan receiver_, the _callback receiver_, the _callback function_, the `asset` and the `amount`.

When the `initiator` calls `flash` in a `lender`. The `lender` will then transfer the `amount` of `asset` to the _loan receiver_.

The `lender`, after transferring `amount` of `asset` to the _loan receiver_, will execute the _callback function_ on the _callback receiver_. The `lender` will include in this _callback function_ call a number of parameters related to the loan as defined in this standard.

The `amount` and `fee` need to be transferred to a `repayment receiver` before the end of the `flash` call. The `fee` can be set to zero `asset`.

The _callback function_ can return any arbitrary data which will be received by the `initiator` as the return value of the `flash` call.

The lender decides which `assets` to support. The lender can decide to support all possible assets.

### Lender Specification

A `lender` MUST implement the [ERC-7399](./eip-7399.md) interface.

```solidity
// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.6.0 <0.9.0;

import { IERC20 } from "./IERC20.sol";

interface IERC7399 {
    /// @dev The amount of currency available to be lent.
    /// @param asset The loan currency.
    /// @return The amount of `asset` that can be borrowed.
    function maxFlashLoan(
        address asset
    ) external view returns (uint256);

    /// @dev The fee to be charged for a given loan. Returns type(uint256).max if the loan is not possible.
    /// @param asset The loan currency.
    /// @param amount The amount of assets lent.
    /// @return The amount of `asset` to be charged for the loan, on top of the returned principal.
    function flashFee(
        IERC20 asset,
        uint256 amount
    ) external view returns (uint256);

    /// @dev Initiate a flash loan.
    /// @param loanReceiver The address receiving the flash loan
    /// @param asset The asset to be loaned
    /// @param amount The amount to loaned
    /// @param data The ABI encoded user data
    /// @param callback The address and signature of the callback function
    /// @return result ABI encoded result of the callback
    function flash(
        address loanReceiver,
        ERC20 asset,
        uint256 amount,
        bytes calldata data,
        /// @dev callback. This is a combination of the callback receiver address, and the signature of callback
        /// function. It is encoded packed as 20 bytes + 4 bytes.
        /// @dev the return of the callback function is not encoded in the parameter, but must be `returns (bytes
        /// memory)` for compliance with the standard.
        /// @param initiator The address that called this function
        /// @param paymentReceiver The address that needs to receive the amount plus fee at the end of the callback
        /// @param asset The asset to be loaned
        /// @param amount The amount to loaned
        /// @param fee The fee to be paid
        /// @param data The ABI encoded data to be passed to the callback
        /// @return result ABI encoded result of the callback
        function(address, address, IERC20, uint256, uint256, bytes memory) external returns (bytes memory) callback
    )
        external
        returns (bytes memory);
}

```

The `maxFlashLoan` function MUST return the maximum available loan for `asset`. The `maxFlashLoan` function MUST NOT revert. If no flash loans for the specified `asset` are possible, the value returned MUST be zero.

The `flashFee` function MUST return the fee charged for a loan of `amount` `asset`. The `flashFee` function MUST NOT revert. If a flash loan for the specified `asset` and `amount` is not possible, the value returned MUST be `type(uint256).max`.

The `flash` function MUST execute the callback passed on as an argument.

```solidity
bytes memory result = callback(msg.sender, address(this), asset, amount, _fee, data);
```

The `flash` function MUST transfer `amount` of `asset` to _loan receiver_ before executing the callback.

The `flash` function MUST include `msg.sender` as the `initiator` in the callback.

The `flash` function MUST NOT modify the `asset`, `amount` and `data` parameter received, and MUST pass them on to the callback.

The `flash` function MUST include a `fee` argument in the callback with the fee to pay for the loan on top of the principal, ensuring that `fee == flashFee(asset, amount)`.

Before the end of the callback, the `asset` balance of `payment receiver` MUST have increased by `amount + fee` from the amount at the beginning of the callback, or revert if this is not true.

The return of the `flash` function MUST be the same as the return from the callback.

### Receiver Specification

A _callback receiver_ of flash loans MUST implement one or more external functions with the following arguments and return value:

```solidity
/// @dev This function can have any name and be overloaded.
/// @param initiator The address that called this function
/// @param paymentReceiver The address that needs to receive the amount plus fee at the end of the callback
/// @param asset The asset to be loaned
/// @param amount The amount to loaned
/// @param fee The fee to be paid
/// @param data The ABI encoded data to be passed to the callback
/// @return result ABI encoded result of the callback
function(address, address, IERC20, uint256, uint256, bytes memory) external returns (bytes memory) callback;
```

## Rationale

The interfaces described in this ERC have been chosen as to cover the known flash lending use cases, while allowing for safe and gas efficient implementations.

`maxFlashLoan` and `flashFee` return numerical values on impossible loans to allow sorting lenders without having to deal with reverts.

`maxFlashLoan` returns a value that is consistent with an impossible loan when the `lender` is not able to serve the loan.

`flashFee` returns a value that is consistent with an impossible loan when the `lender` is not able to serve the loan.

`flash` has been chosen as a function name as a verb which is descriptive enough, unlikely to clash with other functions in the `lender`, and including both the use cases in which the assets lent are held or minted by the `lender`.

Existing flash lenders all provide flash loans of several asset types from the same contract. Providing a `asset` parameter in both the `flash` and callback functions matches closely the observed functionality.

A `bytes calldata data` parameter is included for the `initiator` to pass arbitrary information to the `receiver`. The `receiver` can pass arbitrary information back to the `initiator` using the `bytes memory` return value.

A `initiator` will often be required in the callback function, which the `lender` knows as `msg.sender`. An alternative implementation which would embed the `initiator` in the `data` parameter by the caller would require an additional mechanism for the receiver to verify its accuracy, and is not advisable.

A _loan receiver_ is taken as a parameter to allow flexibility on the implementation of separate loan initiators, loan receivers, and callback receivers. This parameter is not passed on to the _callback receiver_ on the grounds that it will be often the same as _callback receiver_ and when not, it can be encoded in the `data` by the `initiator`.

A `payment receiver` allows for the same flexibility on repayments as in borrows. Control flow and asset flow are independent.

The `amount` will be required in the callback function, which the `lender` took as a parameter. An alternative implementation which would embed the `amount` in the `data` parameter by the caller would require an additional mechanism for the receiver to verify its accuracy, and is not advisable.

A `fee` will often be calculated in the callback function, which the callback receiver must be aware of for repayment. Passing the `fee` as a parameter instead of appended to `data` is simple and effective.

Arbitrary callback functions on callback receivers allows to implement different behaviours to flash loans on callback receivers without the need for encoding a function router using the `data` argument. A function call type is 24 bytes of which the first 20 bytes are the target address and the last 4 bytes are the function signature.

The `amount + fee` are pushed to the `payment receiver` to allow for the segregation of asset and control flows. While a "pull" architecture is more prevalent, "push" architectures are also common. For those cases where the `lender` can't implement a "push" architecture, a simple wrapper contract can offer this proposal's external interface, while using liquidity from the `lender` using a "pull" architecture.

## Backwards Compatibility

This EIP is a successor of [ERC-3156](./eip-3156.md). While not directly backwards compatible, a wrapper contract offering this proposal's external interface with liquidity obtained from an ERC-3156 flash `lender` is trivial to implement.

## Security Considerations

### Verification of callback arguments

The arguments of the flash loan callbacks are expected to reflect the conditions of the flash loan, but cannot be trusted unconditionally. They can be divided in two groups, that require different checks before they can be trusted to be genuine.

1. No arguments can be assumed to be genuine without some kind of verification. `initiator`, `asset` and `amount` refer to a past transaction that might not have happened if the caller of the callback decides to lie. `fee` might be false or calculated incorrectly. `data` might have been manipulated by the caller.
2. To trust that the value of `initiator`, `asset`, `amount` and `fee` are genuine a reasonable pattern is to verify that the callback caller is in a whitelist of verified flash lenders. Since often the caller of `flash` will also be receiving the callback this will be trivial. In all other cases flash lenders will need to be approved if the arguments in the callback are to be trusted.
3. To trust that the value of `data` is genuine, in addition to the check in point 1, it is recommended to verify that the `initiator` belongs to a group of trusted addresses. Trusting the `lender` and the `initiator` is enough to trust that the contents of `data` are genuine.

### Flash lending security considerations

#### Automatic approvals

Any `receiver` that repays the `amount` and `fee` received as arguments needs to include in the callback a mechanism to verify that the initiator and `lender` are trusted.

Alternatively, the callback receiver can implement permissioned functions that set state variables indicating that a flash loan has been initiated and what to expect as `amount` and `fee`.

Alternatively, the callback receiver can verify that `amount` was received by the `loanReceiver` and use its own heuristics to determine if a `fee` is fair and the loan repaid, or the transaction reverted.

### Flash minting external security considerations

The typical quantum of assets involved in flash mint transactions will give rise to new innovative attack vectors.

#### Spot Oracle Manipulation

The supply of a flash-mintable asset can be easily manipulated, so oracles that take the supply of the flash-mintable asset into account must either discount amounts that were flash-minted, produce data that is averaged over time, or find some other solution to the varying supply.

#### Arithmetic Overflow and Underflow

If the flash mint provider does not place any limits on the amount of flash mintable assets in a transaction, then anyone can flash mint $2^256-1$ amount of assets.

The protocols on the receiving end of the flash mints will need to ensure their contracts can handle this, either by using a compiler that embeds overflow protection in the smart contract bytecode, or by setting explicit checks.

### Flash minting internal security considerations

The coupling of flash minting with business specific features in the same platform can easily lead to unintended consequences.

#### Treasury Draining

Assume a smart contract that flash lends its native asset. The same smart contract borrows from a third party when users burn the native asset. This pattern would be used to aggregate in the smart contract the collateralized debt of several users into a single account in the third party. The flash mint could be used to cause the `lender` to borrow to its limit, and then pushing interest rates in the underlying `lender`, liquidate the flash `lender`:

1. Flash mint from `lender` a very large amount of FOO.
2. Redeem FOO for BAR, causing `lender` to borrow from `underwriter` all the way to its borrowing limit.
3. Trigger a debt rate increase in `underwriter`, making `lender` undercollateralized.
4. Liquidate the `lender` for profit.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
