Flash Loans

SoftLink Flash Loans V0

API Design

Each deployed reserve contains the following two accessible functions for performing flash loans:

struct FlashLoanParams {
    address receiver;
    uint256 amount;
    bytes params;
}

// NOTE: Can only be executed on reserves configured to manage currencies native to the network (ETH, FTM, NEAR, SOL, etc.)
function flashLoanETH(FlashLoanParams calldata params) public returns (bool)

// NOTE: Can only be executed on reserves configured to manage ERC20 tokens (DAI, AAVE, COMP, ETH/DAI, etc.)
function flashLoanERC20(FlashLoanParams calldata params) public returns (bool)

The following is an example of how one can design a simple smart contract to perform a flash loan on the protocol:

pragma solidity ^0.8.10;

import "./CoreReserve.sol";
import "./CoreFlashLoanReceiver.sol";
import "./dependencies/openzeppelin/SafeMath.sol";

contract MockCoreFlashLoanReceiver is CoreFlashLoanReceiver {
    using SafeMath for uint256;

    constructor() {}

    function executeOperation(
        address _reserve,
        uint256 _amount,
        uint256 _fee,
        bytes calldata _params
    ) external returns (bool) {
        // Perform any logic with the loan
        (bool success, ) = address(0).call(_params);
        require(success, "Strategy failed.");

        // Return the funds + amount fee
        (, , bool isNativeTokenReserve, address reserveToken) = CoreReserve(
            payable(_reserve)
        ).reserveData();

        transferInternal(
            payable(_reserve),
            reserveToken,
            isNativeTokenReserve,
            _amount.add(_fee)
        );

        return true;
    }

    function tI(
        address payable _reserve,
        address _reserveToken,
        bool _isNativeReserve,
        uint256 _amount
    ) public {
        transferInternal(_reserve, _reserveToken, _isNativeReserve, _amount);
    }

    function gBI(
        address payable _reserve,
        address _reserveToken,
        bool _isNativeReserve
    ) public view returns (uint256) {
        return getBalanceInternal(_reserve, _reserveToken, _isNativeReserve);
    }
}

// Option 1: Create a new core flash loan receiver to perform the flash loan
MockCoreFlashLoanReceiver mockCoreFlashLoanReceiver = new MockCoreFlashLoanReceiver();

// Option 2: Attach to an existing receiver on the network
IFlashLoanReceiver mockCoreFlashLoanReceiver = IFlashLoanReceiver(0x123...);

// NOTE: Initial deposits will most likely be handled on the UI
uint256 initialDeposit = 333 ether;
initialETHSnipingReserve.deposit{value: initialDeposit}(
    initialDeposit,
    address(mockCoreFlashLoanReceiver)
);

// Execute the flash loan
uint256 loanAmount = 22 ether;
initialETHSnipingReserve.flashLoanETH(
    CoreReserve.FlashLoanParams({
        receiver: address(mockCoreFlashLoanReceiver),
        amount: loanAmount,
        params: bytes("")
    })
);

Last updated