Flash Loan

Developer documentation on how to utilize CROSS for flash loan utility

Overview

Flash loan functionality is healthy for any ecosystem as they assist in ensuring efficient market pricing via arbitrage, healthy collateral levels in lending protocols via flash liquidation, and much more.

Flash loans are a feature designed for developers, due to the technical knowledge required to execute one. Flash Loans allow you to borrow any available amount of assets without putting up any collateral, as long as the liquidity is returned to the protocol within one block transaction. To do a Flash Loan, you will need to build a contract that requests a Flash Loan. The contract will then need to execute the instructed steps and pay back the loan + interest and fees all within the same transaction.

Read our article for a brief overview on what this is and what it means for the ecosystem: https://medium.com/@avtoCROSS/product-extension-flash-loan-enabled-71b090433152

Otherwise, learn more about the fundamentals of Flash Loans in this introductory primer and this more in-depth study for those who wish to better understand it.

Documentation

Some CROSS pools have flash loan functionalities enabled for a small, industry-standard 0.08% fee.

Currently, xUSD 3Pool (0x43F3671b099b78D26387CD75283b826FD9585B60) is the only supported pool for flash loan functionalities:

  • USDC: 0xc21223249CA28397B4B6541dfFaEcC539BfF0c59

  • USDT: 0x66e428c3f67a68878562e79A0234c1F83c208770

  • DAI: 0xF2001B145b43032AAF5Ee2884e456CCd805F677D

function flashLoan(
    address receiver,
    IERC20 token,
    uint256 amount,
    bytes memory params
) external;

Caller must provide a valid receiver address that inherits IFlashLoanReceiver interface.

function executeOperation(
    address pool,
    address token,
    uint256 amount,
    uint256 fee,
    bytes calldata params
) external;

Upon finishing executeOperation, the pool must have the initial liquidity back along with the associated fee. If the requirement is not met, then the transaction will fail.

Contract Template

We provide a basic example of a flash loan borrower contract:

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.12;

import "@openzeppelin/contracts@3.4.1/math/SafeMath.sol";
import "@openzeppelin/contracts@3.4.1/token/ERC20/IERC20.sol";

/**
 * @title IFlashLoanReceiver interface
 * @notice Interface for the Saddle fee IFlashLoanReceiver. Modified from Aave's IFlashLoanReceiver interface.
 * https://github.com/aave/aave-protocol/blob/4b4545fb583fd4f400507b10f3c3114f45b8a037/contracts/flashloan/interfaces/IFlashLoanReceiver.sol
 * @author Aave
 * @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract
 */

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

/**
 * @title ISwapFlashLoan interface
 * @notice Interface for the SwapFlashLoan contract.
 */

interface ISwapFlashLoan {
    function flashLoan(
        address receiver,
        IERC20 token,
        uint256 amount,
        bytes memory params
    ) external;
}

/**
 * @title FlashLoanBorrowerExample contract
 * @notice Reference implementation of FlashLoan system's using.
 */

contract FlashLoanBorrowerExample is IFlashLoanReceiver {
    using SafeMath for uint256;

    // Typical executeOperation function should do the 3 following actions
    // 1. Check if the flashLoan was successful
    // 2. Do actions with the borrowed tokens
    // 3. Repay the debt to the `pool`

    function executeOperation(
        address pool,
        address token,
        uint256 amount,
        uint256 fee,
        bytes calldata params
    ) external override {
        // 1. Check if the flashLoan was valid
        require(
            IERC20(token).balanceOf(address(this)) >= amount,
            "flashloan is broken?"
        );

        // 2. Do actions with the borrowed token
        bytes32 paramsHash = keccak256(params);
        
        if (paramsHash == keccak256(bytes("nothing"))) {
            return;
        } else if (paramsHash == keccak256(bytes("increase_balance_1"))) {
            // SOME CODE TO INTERACT WITH OTHER CONTRACTS
            // ...
        } else if (paramsHash == keccak256(bytes("decrease_balance_2"))) {
            // SOME CODE TO INTERACT WITH OTHER CONTRACTS
            // ...
        }

        // 3. Payback debt
        uint256 totalDebt = amount.add(fee);
        IERC20(token).transfer(pool, totalDebt);
    }

    // MAIN CALLING METHOD
    function getFlashLoan(
        ISwapFlashLoan swap,
        IERC20 token,        // required token (from pool)
        uint256 amount,      // loan amount (weis)
        string memory params // some params
    ) external {
        // Calling of pool supports FlashLoan
        swap.flashLoan(
            address(this),
            token,
            amount,
            bytes(params)
        );
    }
};

Here, for getting of Flash-Loan and using of it you need to call getFlashLoan method only.

Example of a loan getting in 1000 USDC:

getFlashLoan(
    0x43F3671b099b78D26387CD75283b826FD9585B60, // xUSD 3Pool
    0xc21223249CA28397B4B6541dfFaEcC539BfF0c59, // USDC
    1000000000, // 1000 USDC
    "increase_balance_1"
)

Last updated