If you're familiar with Solidity, the best place to start is to copy the contracts in our Flash Loan Truffle box. The contract you call is Flashloan.sol
with function flashloan()
.
If you want to follow a step by step procedure, see below.
To interact with the Flash Loan functionality of the Aave protocol, a basic understanding of Solidity and its inheritance techniques are needed.
Your contract should inherit from the FlashLoanReceiverBase
contract, which can be found here (Solidity ^0.5.0) or here (Solidity ^0.6.6).
Your contract should call the flashLoan()
function of the LendingPool
. For more information on the flashLoan()
function, see the documentation here.
An example of your contract calling the LendingPool
:
/*** Flash Loan of 1000 DAI*/address receiver = address(this) // Can also be a separate contractaddress asset = "0x6b175474e89094c44da98b954eedeac495271d0f"; // Daiuint256 amount = 1000 * 1e18;// If no params are needed, use an empty params:bytes memory params = "";// Else encode the params like below (bytes encoded param of type `address` and `uint`)// bytes memory params = abi.encode(address(this), 1234);ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool());lendingPool.flashLoan(address(this), asset, amount, params);
If you need to pass in arbitrary parameters for the executeOperation()
to use, then you can pass in any bytes
encoded data via the params_
input. Otherwise, you can pass in an empty bytes
encoded value as shown above.
When your contract calls lendingPool.flashLoan()
, our LendingPool
contract completes some sanity checks, transfers the requested _amount
of _reserve
asset to the receiver
you specified, then calls executeOperation()
on the receiver
contract your specified.
Your receiver
contract must have a function with the exact function signature as the following:
function executeOperation(address _reserve, uint256 _amount, uint256 _fee, bytes memory _params) external
Before the end of your executeOperation()
function, you must payback the Flash Loan amount
and the fee
. If this action is not performed, the transaction will be reverted.
In our example below, we have inherited from the FlashLoanReceiverBase
contract so can simply call transferFundsBackToPoolInternal()
to repay the loan and fee amount.
An example implementation of your receiver
contract that receives the Flash Loan:
pragma solidity ^0.6.6;import "./FlashLoanReceiverBase.sol";import "./ILendingPoolAddressesProvider.sol";import "./ILendingPool.sol";contract Flashloan is FlashLoanReceiverBase {constructor(address _addressProvider) FlashLoanReceiverBase(_addressProvider) public {}/**This function is called after your contract has received the flash loaned amount*/function executeOperation(address _reserve,uint256 _amount,uint256 _fee,bytes calldata _params)externaloverride{require(_amount <= getBalanceInternal(address(this), _reserve), "Invalid balance, was the flashLoan successful?");//// Your logic goes here.// !! Ensure that *this contract* has enough of `_reserve` funds to payback the `_fee` !!//uint totalDebt = _amount.add(_fee);transferFundsBackToPoolInternal(_reserve, totalDebt);}function flashloan() public onlyOwner {/*** Flash Loan of 1000 DAI*/address receiver = address(this) // Can also be a separate contractaddress asset = "0x6b175474e89094c44da98b954eedeac495271d0f"; // Daiuint256 amount = 1000 * 1e18;// If no params are needed, use an empty params:bytes memory params = "";// Else encode the params like below (bytes encoded param of type `address` and `uint`)// bytes memory params = abi.encode(address(this), 1234);ILendingPool lendingPool = ILendingPool(addressesProvider.getLendingPool());lendingPool.flashLoan(address(this), asset, amount, params);}}
pragma solidity ^0.5.0;import "@openzeppelin/contracts/math/SafeMath.sol";import "../tokens/MintableERC20.sol";import "../../flashloan/base/FlashLoanReceiverBase.sol";import "../../configuration/LendingPoolAddressesProvider.sol";import "../../configuration/NetworkMetadataProvider.sol";contract FlashLoanReceiverExample is FlashLoanReceiverBase {using SafeMath for uint256;constructor(LendingPoolAddressesProvider _provider)FlashLoanReceiverBase(_provider)public {}function executeOperation(address _reserve,uint256 _amount,uint256 _fee,bytes memory _params) external {//check the contract has the specified balancerequire(_amount <= getBalanceInternal(address(this), _reserve),"Invalid balance for the contract");/**CUSTOM ACTION TO PERFORM WITH THE BORROWED LIQUIDITYExample of decoding bytes param of type `address` and `uint`(address sampleAddress, uint sampleAmount) = abi.decode(_params, (address, uint));*/transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));}}