FlashLoans

Flashloan documentations

The Risk Protocol provides two types of Flashloans:

  1. Flashloan of Underlying Assets

  2. Flashloan of Unwanted Assets on Wrapped Smart Tokens

Flashloan of Underlying Assets

This type of flashloan is similar to those offered by protocols like AAVE. We provide access to the underlying tokens locked in our smart contracts as flashloans. These loans are issued against a fixed fee and must be repaid within the same transaction.

  • The flashLoan method is exposed on the smart token contracts, making it accessible via the RiskON/RiskOFF token contracts.

Flashloan Method on Smart Contracts

The flashloan method to be called on the smart contract is as follows:

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

where

  • receiver: The address of the contract that will receive the flashloan and must implement the IFlashLoanReceiver interface

  • amount: self descriptive

  • params: any parameters that would be used in the flashloan receiver

The IFlashLoanReceiver Interface

The receiver contract must implement the following interface to handle the flashloan:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.9;

interface IFlashLoanReceiver {
  function executeOperation(
    address[] calldata assets,
    uint256[] calldata amounts,
    uint256[] calldata premiums,
    address initiator,
    bytes calldata params
  ) external returns (bool);
}

Note:

The receiver contract must approve the smart token contract to spend the underlying token on it's behalf.

Sample FlashLoan Receiver Contract

Below is an example of a simple receiver contract that implements the IFlashLoanReceiver interface:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.9;

import "../interfaces/flashloan/IFlashLoanReceiver.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";

/**
 * @title MockFlashLoanReceiver_UND
 * @dev This contract implements the IFlashLoanReceiver interface and serves as a mock receiver for flashloan operations.
 */
contract MockFlashLoanReceiver_UND is IFlashLoanReceiver {
   using SafeMathUpgradeable for uint256;
   using SafeERC20 for IERC20;

   address public immutable LENDING_POOL;
   bool public isApproved;
   bool public mockReturn;

   event FlashLoanExecuted(
       address[] assets,
       uint256[] amounts,
       uint256[] premiums,
       address initiator
   );


   constructor(address _LENDING_POOL) {
       LENDING_POOL = _LENDING_POOL;
       mockReturn = true;
   }


   function setApprovalStatus(bool _approved) external {
       isApproved = _approved;
   }

   function updateMockReturn(bool return_) external {
       mockReturn = return_;
   }


   function executeOperation(
       address[] calldata assets,
       uint256[] calldata amounts,
       uint256[] calldata premiums,
       address initiator,
       bytes calldata params
   ) external override returns (bool) {
       for (uint256 i = 0; i < assets.length; i++) {
           // Perform operations with the loaned assets (e.g., arbitrage, liquidation)

           // Approve the LENDING_POOL to pull the repay amount
           if (isApproved) {
               IERC20(assets[i]).safeApprove(
                   address(LENDING_POOL),
                   amounts[i].add(premiums[i])
               );
           }
       }

       // Emit an event to log the flashloan execution
       emit FlashLoanExecuted(assets, amounts, premiums, initiator);

       // Return the success status
       return mockReturn;
   }
}

Flashloan of Unwanted Assets on Wrapped Smart Tokens

This type of flashloan is unique to our protocol, offering users access to pools of excess or unwanted smart tokens on the wrapped smart token contracts.

Scenario Explanation

To understand this concept better, let's consider an example involving BTC:

  • We have BTC RiskON and BTC RiskOFF as smart tokens.

  • Correspondingly, we have wBTC RiskON and wBTC RiskOFF as wrapped ERC20 tokens.

Each wrapped token contract (wBTC RiskON and wBTC RiskOFF) functions like a separate wallet, holding a certain amount of their respective smart tokens. (More details can be found in the Wrapped Smart Token section).

During a rebalance, depending on market conditions, one of the wrapped smart token contracts might end up holding not only its respective smart tokens (the wanted tokens) but also some alternate smart tokens (the unwanted tokens). This means the wrapped smart token now contains some excess or unwanted tokens.

Flashloan Mechanism

In this context, our flashloan feature allows users to borrow these unwanted tokens. The borrowed amount must be repaid in the wanted tokens, but with a special discount compared to market prices. This incentivizes rapid liquidation of the unwanted tokens, helping to maintain balance in the system.

The flashloan method is exposed on the wrapped smart token contracts, making it accessible via the wRiskON/wRiskOFF token contracts.

Flashloan Method on Wrapped Smart Token Contracts

The flashloan method available on these contracts is as follows:

    function flashLoan(
        address receiver,
        uint256 amount,
        bytes memory encodedData,
        bytes memory signature,
        bytes memory params
    )
        external

where

  • receiver: The address of the contract that will receive the flashloan and must implement the IFlashLoanReceiverAlt interface.

  • amount: self descriptive

  • params: Any additional parameters that would be used within the flashloan receiver.

  • encodedData: Encoded market prices retrieved from our API.

  • signature: The signature of the encoded market prices from our API.

The IFlashLoanReceiverAlt Interface

The receiver contract must implement the IFlashLoanReceiverAlt interface to handle the flashloan operation for unwanted assets on wrapped smart tokens.

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.9;

//Used by the flashloan in the wrapped smart token
interface IFlashLoanReceiverAlt {
    function executeOperation(
        uint256 loanAmount,
        address repayToken,
        uint256 repayAmount,
        address initiator,
        bytes calldata params
    ) external returns (bool);
}

Interface Parameters

  • loanAmount: The amount of unwanted tokens borrowed through the flashloan.

  • repayToken: The address of the token to be used for repayment (the wanted token).

  • repayAmount: The total amount of the repayToken that needs to be repaid, including any fees or discounts.

  • initiator: The address of the entity that initiated the flashloan.

  • params: Additional parameters that may be required by the receiver contract during the flashloan operation.

Note: The receiver contract must approve the wrapped smart token contract to spend the wanted smart tokens for the repayment of the loan.

Sample FlashLoan Receiver Contract

Below is an example of a simple receiver contract that implements the IFlashLoanReceiverAlt interface:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.9;

import "../interfaces/flashloan/IFlashLoanReceiverAlt.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";

/**
 * @title MockFlashLoanReceiver_UnwantedTokens
 * @dev This contract implements the IFlashLoanReceiverAlt interface and serves as a mock receiver for flashloan operations involving unwanted tokens.
 */
contract MockFlashLoanReceiver_UnwantedTokens is IFlashLoanReceiverAlt {
    using SafeMathUpgradeable for uint256;
    using SafeERC20 for IERC20;

    address public immutable LENDING_POOL;
    bool public isApproved;
    bool public mockReturn;


    event FlashLoanExecuted(
        uint256 loanAmount,
        address repayToken,
        uint256 repayAmount,
        address initiator
    );


    constructor(address _LENDING_POOL) {
        LENDING_POOL = _LENDING_POOL;
        mockReturn = true;
    }

   
    function setApprovalStatus(bool _approved) external {
        isApproved = _approved;
    }

  
    function updateMockReturn(bool return_) external {
        mockReturn = return_;
    }

  
    function executeOperation(
        uint256 loanAmount,
        address repayToken,
        uint256 repayAmount,
        address initiator,
        bytes calldata params
    ) external override returns (bool) {
        // @note The user is expected to perform operations that ensure the repayment of tokens

        // Approve the LENDING_POOL to pull the repay amount
        if (isApproved) {
            IERC20(repayToken).safeApprove(
                address(LENDING_POOL),
                repayAmount
            );
        }

        // Emit an event to log the flashloan execution
        emit FlashLoanExecuted(loanAmount, repayToken, repayAmount, initiator);

        // Return the success status
        return mockReturn;
    }
}

Last updated