Flash loan arbitrage on Uniswap and SushiSwap

Create a flash loan arbitrage Solidity smart contract. Flash loans are a form of uncollateralized lending where a borrower must repay the funds within the same blockchain transaction. This sounds complex but it is easy to learn. In this tutorial I will explain the flash loan process in more detail and will show you how to combine it with an arbitrage swap on two decentralized exchanges (Uniswap & SushiSwap). Create a flash loan arbitrage trading bot by following the steps below.

Flash loans on the blockchain

A flash loan is an instant loan that is issued and repaid in the same blockchain block. This is not a loan you can initiate on a website or application as it must be called using a program. The loan is valid for several seconds and if the total amount of the loan is not paid back by the end of the block time the entire transaction is automatically rolled back.

Different decentralized platforms offer flash loans with different terms. Some flash loans are free to borrow funds and some loans charge a small transaction fee. This tutorial will focus on creating a flash loan using Uniswap. This process is very similar to other decentralized platforms.

Arbitrage trading on the blockchain

Arbitrage is the process of purchasing and selling the same asset in different markets at the same time. The goal is to profit from small differences in the asset’s listed price on different exchanges. This process exploits small price differences in identical or similar financial instruments. There are many different types of arbitrage strategies (cross asset, market neutral, tax, etc.) and for this exercises we will focus on price arbitrage (buying on one exchange and selling on another exchange) with the goal of making money on the price differences.

Now let take this a step further and use a flash loan to borrow a large sum of money to execute an arbitrage trade on two decentralized exchanges. If you combine an instant loan with an arbitrage trading strategy you have a very powerful tool.

Flash loan arbitrage Solidity smart contract

The process flow below details how the Solidity smart contract will work. At a high level it will:

  • Borrow tokens on Uniswap
  • Sell these tokens on Sushiswap
  • Repay the loan on Uniswap
Flash Loan Solidity Smart Contract uniswap and sushiswap

To understand how the contract works in detail read the comments in the code below. For more information on Uniswap flash swaps read their documentation and example contracts. This was a Truffle project and it needs to be built by importing the interfaces and library below:

  • import ‘./IERC20.sol’;
  • import ‘./IUniswapV2Router02.sol’;
  • import ‘./IUniswapV2Pair.sol’;
  • import ‘./IUniswapV2Factory.sol’
  • import ‘./UniswapV2Library.sol’;
pragma solidity ^0.5.16;
 
// import required interfaces
 import './IERC20.sol';
 import './IUniswapV2Router02.sol';
 import './IUniswapV2Pair.sol';
 import './IUniswapV2Factory.sol'
 import './UniswapV2Library.sol';


contract FlashLoanArbitrage {

  //uniswap factory address
  address public factory;

  // trade deadline used for expiration
  uint constant deadline = now + 100;

  //create pointer to the sushiswapRouter
  IUniswapV2Router02 public sushiSwapRouter;

  constructor(address _factory, address _sushiSwapRouter) public {

  // create uniswap factory
  factory = _factory;  

  // create sushiswapRouter 
  sushiSwapRouter = IUniswapV2Router02(_sushiSwapRouter);
  }



  // trader needs to monitor for arbitrage opportunities with a bot or script
  // this is the function that trader will call when an arbitrage opportunity exists
  // tokens are the addresses that you want to trade
  // this first function will create the flash loan on uniswap
  // one of the amounts will be 0 and the other amount will be the amount you want to borrow
function executeTrade(address token0, address token1, uint amount0, uint amount1) external {

  // get liquidity pair address for tokens on uniswap
  address pairAddress = IUniswapV2Factory(factory).getPair(token0, token1); 

  // make sure the pair exists in uniswap 
  require(pairAddress != address(0), 'Could not find pool on uniswap'); 

  // create flashloan 
  // create pointer to the liquidity pair address 
  // to create a flashloan call the swap function on the pair contract 
  // one amount will be 0 and the non 0 amount is for the token you want to borrow 
  // address is where you want to receive token that you are borrowing
  // bytes can not be empty.  Need to inculde some text to initiate the flash loan 
  // if bytes is empty it will initiate a traditional swap 
  IUniswapV2Pair(pairAddress).swap(amount0, amount1, address(this), bytes('flashloan'));
 }



  // After the flashloan is created the below function will be called back by Uniswap
  // Uniswap is expecting the function to be named uniswapV2Call
  // the parameters below will be sent
  // sender is the smart contract address
  // amount will be the amount borrowed from the flashloan and other amount will be 0
  // bytes is the calldata passed in above
function uniswapV2Call(address _sender, uint _amount0, uint _amount1, bytes calldata _data) external {

  // the path is the array of addresses to capture pricing information 
  address[] memory path = new address[](2); 
   
  // get the amount of tokens that were borrowed in the flash loan amount 0 or amount 1 
  // call it amountTokenBorrowed and will use later in the function 
  uint amountTokenBorrowed = _amount0 == 0 ? _amount1 : _amount0; 

  // get the addresses of the two tokens from the uniswap liquidity pool 
  address token0 = IUniswapV2Pair(msg.sender).token0(); 
  address token1 = IUniswapV2Pair(msg.sender).token1(); 

  // make sure the call to this function originated from
  // one of the pair contracts in uniswap to prevent unauthorized behavior
  require(msg.sender == UniswapV2Library.pairFor(factory, token0, token1), 'Invalid Request');

  // make sure one of the amounts = 0 
  require(_amount0 == 0 || _amount1 == 0);

  // create and populate path array for sushiswap.  
  // this defines what token we are buying or selling 
  // if amount0 == 0 then we are going to sell token 1 and buy token 0 on sushiswap 
  // if amount0 is not 0 then we are going to sell token 0 and buy token 1 on sushiswap 
  path[0] = _amount0 == 0 ? token1 : token0; 
  path[1] = _amount0 == 0 ? token0 : token1; 

  // create a pointer to the token we are going to sell on sushiswap 
  IERC20 token = IERC20(_amount0 == 0 ? token1 : token0);
  
  // approve the sushiSwapRouter to spend our tokens so the trade can occur             
  token.approve(address(sushiSwapRouter), amountTokenBorrowed);

  // calculate the amount of tokens we need to reimburse uniswap for the flashloan 
  uint amountRequired = UniswapV2Library.getAmountsIn(factory, amountTokenBorrowed, path)[0]; 
  
  // finally sell the token we borrowed from uniswap on sushiswap 
  // amountTokenBorrowed is the amount to sell 
  // amountRequired is the minimum amount of token to receive in exchange required to payback the flash loan 
  // path what we are selling or buying 
  // msg.sender address to receive the tokens 
  // deadline is the order time limit 
  // if the amount received does not cover the flash loan the entire transaction is reverted 
  uint amountReceived = sushiSwapRouter.swapExactTokensForTokens( amountTokenBorrowed, amountRequired, path, msg.sender, deadline)[1]; 

  // pointer to output token from sushiswap 
  IERC20 outputToken = IERC20(_amount0 == 0 ? token0 : token1);
 
  // amount to payback flashloan 
  // amountRequired is the amount we need to payback 
  // uniswap can accept any token as payment
  outputToken.transfer(msg.sender, amountRequired);   

  // send profit (remaining tokens) back to the address that initiated the transaction 
  outputToken.transfer(tx.origin, amountReceived - amountRequired);  
 }
}

Try it in Remix

Notice how a different token was used to pay back the Uniswap loan. Uniswap will convert the funds to the correct amount to ensure the loan is paid back in full.

Build your flash loan arbitrage bot

Modify the smart contract for any DEX

Ethereum

  • Uniswap
  • Sushiswap
  • SashimiSwap
  • Balancer
  • Aave
  • Kyber
  • Mooniswap

Binance Smart Chain

  • MDEX
  • Pancake Swap
  • Burger Swap
  • Bakery Swap

Polygon

  • Quickswap
  • Aave

This code is for learning and entertainment purposes only. This code has not been audited so use at your own risk. Remember smart contracts are experimental and could contain bugs.

Click here for more information about how to use the Ethereum test network and how to obtain test ETH.

Resources

Blockchain Networks

Below is a list of EVM compatible Mainnet and Testnet blockchain networks. Each link contains network configuration, links to multiple faucets for test ETH and tokens, bridge details, and technical resources for each blockchain. Basically everything you need to test and deploy smart contracts or decentralized applications on each chain. For a list of popular Ethereum forums and chat applications click here.

Ethereum test network configuration and test ETH faucet information
Optimistic Ethereum Mainnet and Testnet configuration, bridge details, etc.
Polygon network Mainnet and Testnet configuration, faucets for test MATIC tokens, bridge details, etc.
Binance Smart Chain Mainnet and Testnet configuration, faucets for test BNB tokens, bridge details, etc.
Fanton networt Mainnet and Testnet configuration, faucets for test FTM tokens, bridge details, etc.
Kucoin Chain Mainnet and Testnet configuration, faucets for test KCS tokens, bridge details, etc.

Web3 Software Libraries

You can use the following libraries to interact with an EVM compatible blockchain.

Nodes

Learn how to run a Geth node. Read getting started with Geth to run an Ethereum node.

Fix a transaction

How to fix a pending transaction stuck on Ethereum or EVM compatible chain

Next Review – Learn more about Solidity smart contracts

3 thoughts on “Flash loan arbitrage on Uniswap and SushiSwap

Leave a Reply