Flash Mint

The Flash Mint module allows users to borrow DUSD with the condition that they borrow and pay back their loan in a single transaction with a 0.1% Flash Mint Fee.

The Flash Mint Fee is a value set by Davos. This rate is initially set as 0.1% but may be adjusted as DUSD markets become more efficient.

Built-in Security Mechanism

The Flash Mint functionality of the DUSD stablecoin is designed with a strong focus on security, incorporating various measures to safeguard DUSD. Its most essential feature is that the minted amount must always be returned and burned in the same transaction. This prevents malicious activity or exploitation of DUSD.

Use Cases

While Flash Mint has many use cases, let's focus on some most popular ones.

  • Flash Mint for Arbitrage Flash Mint can allow users to borrow DUSD and swap them on a DEX where currently the price of 1 DUSD is higher than usual.

  • Flash Mint for Liquidations Flash Mint can play a vital role during liquidations. Liquidators can use Flash Mint to access the necessary DUSD tokens to repay a borrower's debt. Subsequently, they can utilize the received collateral to swap back into DUSD and repay the Flash Mint, all within a single transaction. This process allows liquidators to arbitrage the market for risk-free profits.

  • Flash Mint for Farming Flash Mint can allow users to burrow DUSD, use it to obtain a share in a pool or put a pair of tokens in a vault all to get LP Tokens and stake them to collect the staking rewards instantly. Upon collecting the reward, users then can unstake their LP Tokens, withdraw back the liquidity, and repay the Flash Mint.

Dev Details and How-to

Involved Entities

The main involved entities are:

  • flashLender — Davos's smart contract implementing the "server side" of the Flash Mint functionality.

  • flashBorrower — the smart contract implementing the "client side", which EOA can copy, modify, and deploy to interact through with flashLender. A stub example of the smart contract is available later on this page.

  • EOA (Externally Owned Account) — an account that interacts with the copy of flashBorrower they deploy. Effectively, EOA is a developer who copies flashBorrower, modifies, and deploys it on BNB Smart Chain to interact with flashLender through.

flashLender can be used to borrow (mint) and repay (burn) DUSD stablecoins, with a fee, in one transaction. EOA needs to interact with their own deployed copy of flashBorrower, which in turn interacts with flashLender.

Requirements

Pay attention to these requirements while using Flash Mint:

  • Flash Mint fee — 0.1% of the minted sum.

  • Mint limit — $100,000 is the cap user can mint.

Get Flash Mint Fee

To get the fee, call the flashFee(address token, uint256 amount) function that returns the fee amount in 18 Decimals.

Refer to these code examples:

Step-by-step Usage

1. Set Up Your flashBorrower Contract

Your contract must conform to the ERC3156FlashBorrower interface by implementing the onFlashLoan() function.

To interact with flashLender, your contract must implement flashBorrow(token, amount) and onFlashLoan(initiator, token, amount, fee, data), which is a callback function called during the execution of flashLoan().

Implement any custom logic within onFlashLoan().

Here's an example stub contract you can look through to better understand how to implement flashBorrower.

The flashBorrower must implement the IERC3156FlashBorrower, and onFlashLoan() must return the CALLBACK_SUCCESS hash.

pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IERC3156FlashBorrower.sol";
import "../interfaces/IERC3156FlashLender.sol";
contract FlashBorrower is IERC3156FlashBorrower {
    enum Action {NORMAL, OTHER}
    IERC3156FlashLender lender;
    constructor (IERC3156FlashLender lender_) {
        lender = lender_;
    }
    /// @dev ERC-3156 Flash loan callback
    function onFlashLoan(
        address initiator,
        address token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external override returns(bytes32) {
        require(
            msg.sender == address(lender),
            "FlashBorrower: Untrusted lender"
        );
        require(
            initiator == address(this),
            "FlashBorrower: Untrusted loan initiator"
        );
        (Action action) = abi.decode(data, (Action));
        if (action == Action.NORMAL) {
            // do one thing
        } else if (action == Action.OTHER) {
            // do another
        }
        return keccak256("ERC3156FlashBorrower.onFlashLoan");
    }
    /// @dev Initiate a flash loan
    function flashBorrow(
        address token,
        uint256 amount
    ) public {
        bytes memory data = abi.encode(Action.NORMAL);
        uint256 _allowance = IERC20(token).allowance(address(this), address(lender));
        uint256 _fee = lender.flashFee(token, amount);
        uint256 _repayment = amount + _fee;
        IERC20(token).approve(address(lender), _allowance + _repayment);
        lender.flashLoan(this, token, amount, data);
    }
}

2. Understand How to Interact with flashLender

Understand the parameters used in flashLender:

  • CALLBACK_SUCCESS — hash of a custom string, returned on success.

  • token (address) — address of the ERC-20 token that EOA flash-loans.

  • amount (uint256) — amount to mint.

  • receiver (IERC3156FlashBorrower) — address of the flashBorrower deployed by the EOA.

  • data (bytes calldata) — rudimentary non-used parameter left not to change the flashLoan() signature.

Understand the functions you want to interact with:

  • maxFlashLoan(address token) — returns max if token is a supported stablecoin.

  • flashFee(address token, uint256 amount) — applies toll on amount and returns if token is a supported stablecoin.

  • flashLoan(IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data) — mints token amount to receiver with extra data (if any), and expects a return equal to CALLBACK_SUCCESS.

  • accrue() — sends the surplus fee to vow.sol.

If you're curious to understand the MakerDao parameters/constants used in flashLender:

  • vat — address of vat.sol.

  • davosJoin — address of DavosJoin.sol.

  • davos — address of davos.sol.

  • vow — address of vow.sol.

  • max — maximum allowed amount to mint.

  • toll — fee paid when repaying the loan.

  • WAD — 18 Decimals.

  • RAY — 27 Decimals.

  • RAD — 45 Decimals.

  • CALLBACK_SUCCESS — hash of a custom string, returned on success.

For a deeper understanding of the MakerDao contract, such as var, hay, vow, etc, start with the Vat docs and proceed to other smart contracts documented there.

3. Interact with flashLender

flashLender is available by the following addresses:

A typical interaction follows this workflow:

  1. An EOA calls flashBorrow(token, amount) on a borrowing contract flashBorrower.sol.

  2. flashBorrower approves flashLender in advance to repay the loan with a fee. Then it calls the flashLoan(receiver, token, amount, data) function on flashLender which mints a specified amount to the flashBorrower.

  3. The same function flashLoan(receiver, token, amount, data) then calls (CALLBACK) the onFlashLoan(initiator, token, amount, fee, data) function in flashBorrower, which implements the custom logic of whatever the EOA wants to do with the borrowed DUSD, then onFlashLoan() returns the KECCAK256 of ERC3156FlashBorrower.onFlashLoan if its execution was successful. The custom logic is thought-up and implemented completely by the EOA.

  4. flashLender then burns the minted loan and stores the fee as surplus.

The flashBorrower must implement the IERC3156FlashBorrower, and onFlashLoan() must return the CALLBACK_SUCCESS hash.

Close-to-life Usage Example

Look into the tests to find a close-to-life usage example.

Last updated