Implement a Flash Loan

End-users can request flash loans from Xfai pools. Taking advantage of the flash loan capabilities however, requires interacting with the DexfaiV0Core contract directly. Let's briefly look at the flashloan implementation of the DexfaiV0Core contract to get a better grasp how to interact with it:

function flashLoan(
    address _token,
    uint _tokenAmount,
    uint _wethAmount,
    address _to,
    bytes calldata _data
  ) external override pausable singleLock(_token) {
    require(_to != address(0), 'XfaiV0Core INVALID_TO');
    address _weth = wETH;
    address pool = XfaiLibrary.poolFor(_token, factory, poolCodeHash);

    uint tokenBalance = IERC20(_token).balanceOf(pool);
    uint wethBalance = IERC20(_weth).balanceOf(pool);
    require(
      _tokenAmount <= tokenBalance && _wethAmount <= wethBalance,
      'XfaiV0Core: INSUFFICIENT_AMOUNT'
    );

    if (_tokenAmount > 0) IXfaiPool(pool).linkedTransfer(_token, _to, _tokenAmount); // optimistically transfer tokens
    if (_wethAmount > 0) IXfaiPool(pool).linkedTransfer(_weth, _to, _wethAmount); // optimistically transfer tokens

    IXfaiV0FlashLoan(_to).flashLoan(pool, _tokenAmount, _wethAmount, _data);

    require(
      IERC20(_token).balanceOf(pool) * IERC20(_weth).balanceOf(pool) >=
        (tokenBalance + ((_tokenAmount * getTotalFee()) / 10000)) *
          (wethBalance + ((_wethAmount * getTotalFee()) / 10000)),
      'XfaiV0Core: INSUFFICIENT_AMOUNT_RETURNED'
    );

    if (_tokenAmount > 0)
      IXfaiPool(pool).linkedTransfer(_token, infinityNFT, (_tokenAmount * infinityNFTFee) / 10000); // send lnft fee to fee collecting contract
    if (_wethAmount > 0)
      IXfaiPool(pool).linkedTransfer(_weth, infinityNFT, (_wethAmount * infinityNFTFee) / 10000); // send lnft fee to fee collecting contract

    IXfaiPool(pool).update(IERC20(_token).balanceOf(pool), IERC20(_weth).balanceOf(pool));
    emit FlashLoan(_to, _tokenAmount, _wethAmount);
  }

let's have a look at this line of the flashloan function:

IXfaiV0FlashLoan(_to).flashLoan(pool, _tokenAmount, _wethAmount, _data);

We can see that an IDexfaiV0FlashLoan interface is being used to interact with an external smart contract, defined as _to. This is the address where the flash loan gets sent to. To take advantage of flash loans therefore, developers have to implement a smart contract that implements the IDexfaiV0FlashLoan functionalities. Let's now create a mock smart contract capable of receiving a flash loan:

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;

import '../../interfaces/IERC20.sol';

contract MockFlashLoan {
  address token;
  address weth;

  constructor(address _token, address _weth) {
    token = _token;
    weth = _weth;
  }

  function flashLoan(
    address _pool,
    uint _tokenAmount,
    uint _wethAmount,
    bytes calldata /*_data*/
  ) external {
    uint tokenBalance = IERC20(token).balanceOf(address(this)); // used only for testing purposes
    uint wethBalance = IERC20(weth).balanceOf(address(this)); // used only for testing purposes
    /*
      Insert here the lines of code that uses the flash loan.
    */
    if (_tokenAmount != 0) _safeTransfer(token, _pool, tokenBalance);
    if (_wethAmount != 0) _safeTransfer(weth, _pool, wethBalance);
  }

  function _safeTransfer(address _token, address _to, uint256 _value) internal {
    require(_token.code.length > 0);
    (bool success, bytes memory data) = _token.call(
      abi.encodeWithSelector(IERC20.transfer.selector, _to, _value)
    );
    require(success && (data.length == 0 || abi.decode(data, (bool))));
  }
}

We can call the flashloan function of the DexfaiV0Core contract, to activate the logic of our MockFlashLoan contract. This is all it takes to request a flash loan on Xfai.

For a more in depth exploration of the conceptual aspects of Xfai flash loans, visit the Flash Loans section:

Last updated