Decentralized finance or DeFi is all the rage these days. It's easy to see why. It's permissionless, censorship resistant and lets you do interesting things previously unheard of with traditional finance. In this video I'm going to show you how you can borrow thousands of dollars worth of crypto without collateral using "Flash Loans".

Wouldn't it be great if you had a huge pile of cryptocurrency at your disposal to trade and profit like the big dogs? Well now you can with a fairly new concept called a flash loan. A flash loan is simply a way to borrow large sums of crypto using a smart contract. You don't need any background checks or need to put down any collateral either. There's only one catch. The loan needs to be paid back within a single Ethereum transaction. This sounds kind of useless but Ethereum transactions are actually pretty powerful under the hood.

A single Ethereum transaction can execute a whole handful of operations before it is completed. This means you can initiate a flash loan perform some operations and then repay at the very end. If for some reason the transaction would result in the loan not being repaid, Ethereum is smart enough to detect it and the whole transaction is reverted and it's like the transaction never happened. A common use case for a flash loan is arbitrage or buying from one exchange and selling on another for a profit.

In summary a flash loan transaction would look something like this.

  • Borrow funds
  • Buy another asset from Exchange A
  • Sell that asset for a profit on exchange B
  • Repay the loan and keep the profits.

One DeFi platform that allows for using flash loans is Aave and they provide a very simple smart contract for doing so.

Let's create a quick and dirty flash loan.

First pull in some dependencies including SafeMath and some contracts from Aave. Then create a contract that inherits from FlashLoanReceiverBase.

pragma solidity ^0.5.0;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";

import "../../flashloan/base/FlashLoanReceiverBase.sol";
import "../../configuration/LendingPoolAddressesProvider.sol";
import "../../lendingpool/LendingPool.sol";

contract FlashLoanReceiverExample is FlashLoanReceiverBase {
    // Do Stuff
}

Next create some variables for a lending provider and the address of the chainlink token contract so we can borrow some LINK tokens. In the constructor we need to pass the address for the Aave provider contract for the network we are operating on and the chainlink token address. We then call the parent constructor for FlashLoanReceiverBase and then save our contract variables.

using SafeMath for uint256;

LendingPoolAddressesProvider provider;
address chainlink;

constructor(LendingPoolAddressesProvider _provider, address _chainlink)
    FlashLoanReceiverBase(_provider)
    public
{
    provider = LendingPoolAddressesProvider(_provider);
    chainlink = _chainlink;
}

Next we need to implement a function called executeOperation which takes a token address called "_reserve" an amount to borrow, a fee paid to Aave and any extra params we may need.

We first check that there is enough chainlink in the lending pool to borrow then we can do our arbitrage. If all goes well, we should have our borrowed chainlink plus profits.

We then finish by transfering the borrowed amount back to Aave.

function executeOperation(
    address _reserve,
    uint256 _amount,
    uint256 _fee,
    bytes memory _params) external {

    //check the contract has the specified balance
    require(
        _amount <= getBalanceInternal(address(this), _reserve), 
        "Invalid balance for the contract"
    );

    // Buy from exchange A 💰

    // Sell on exchange B 💱

    // PROFIT!!! 🤑🤑🤑🚀🎉

    transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
}

In order to kick off the loan we need a separate function. This will simply take the amount and any extra params. We create an instance of LendingPool and call the flashLoan method with this contract address, the chainlink token address, amount we want to borrow and any extra params.

function initLoan(uint256 _amount, bytes calldata params) public {
    LendingPool lendingPool = lendingPool(provider.getLendingPool());
    lendingPool.flashLoan(address(this), chainlink, _amount, _params);
}

And that's it!