Research Summary: Building a Flash Loan Arbitrage Bot on Infura


The authors explain the underlying concepts behind flash loans and flash swaps. They show how to build your own Ethereum bot, running on Infura, watching for and executing profitable arbitrage opportunities using flash loans.

Core Research Question

How to build a Flash Loan Arbitrage Bot on Infura



  • Arbitrage trading, independent of flash loans or blockchain, is when you have the same asset with two different prices in two different exchanges.

  • Sushiswap is a fork of Uniswap, which means they run on the same contract code. While they’re two different exchanges, we can use the same code to execute the same trade.

  • All Ethereum transactions originate from an Externally Owned Account (EOA), which is an Ethereum address operated by a human.

  • Optimistic transfer allows a user to take uncollateralized loans or swaps and execute a trade as long as the user pays the service back by the end of the trade.

  • Infura is a scalable Web3 Tools and Infrastructure.


  • Flash Loan vs Flash Swap

  • Flash loans require multiple function calls within their execution, something that’s not possible from an EOA. Instead, we will deploy a contract that contains a multi-step process.

  • Optimistic transfer allows a user to take uncollateralized loans or swaps and execute a trade as long as the user pays the service back by the end of the trade. To better understand this mind-bender, let’s take a look at some code.

  • Overall flow of Arbitrage Trading example

    1) Program (“Bot”) is watching the price pairing of ETH-Dai on both Uniswap and Sushiswap

    2) When it spots a profitable arbitrage opportunity, it sends a transaction to a contract we’ve deployed

    3) Within one transaction, the contract:

    > **a)** Uses flash swaps to optimistically borrow an asset from the lower-priced pool
    > **b)** Immediately sells the asset in the higher-priced pool
    > **c)** Repays the flash swap loan and pockets the difference.
  • Infura, a backend structure, is written in Node and we will use our Infura node to watch the price of ETH and Dai on the Uniswap and Sushiswap contracts. Why don’t we rely on the Infura endpoint to get those prices for each new block produced on mainnet.

  • .env

  • Contract Instantiation
// uni/sushiswap ABIs
const UniswapV2Pair = require('./abis/IUniswapV2Pair.json');
const UniswapV2Factory = require('./abis/IUniswapV2Factory.json');
  • provider.on(‘block’)
    Every block time, we will ask Infura to check the price of ETH and Dai in Uniswap and Sushiswap. We’ll then compare those numbers to get the “spread,” or possible profit margin.
provider.on('block', async (blockNumber) => {
    try {
      const sushiReserves = await sushiEthDai.getReserves();
      const uniswapReserves = await uniswapEthDai.getReserves();
  • estimateGas
    Defi transactions like this can be very expensive. There may appear to be a profitable arbitrage, but any profit margin may be eaten up by the cost of gas. An important check of our program is to make sure our gas costs don’t eat into our spread. We do this here and include it in our final check for shouldSendTx.
  const shouldSendTx = shouldStartEth
        ? (gasCost / ETH_TRADE) < spread
        : (gasCost / (DAI_TRADE / priceUniswap)) < spread;
  • Contract
    Basically, the contract acts as an intermediary for us. When our program detects a profitable opportunity, it sends funds and instructions to this contract.
pragma solidity =0.6.6;

import './UniswapV2Library.sol';
import './interfaces/IUniswapV2Router02.sol';
import './interfaces/IUniswapV2Pair.sol';
import './interfaces/IERC20.sol';

contract FlashLoaner {
  address immutable factory;
  uint constant deadline = 10 days;
  IUniswapV2Router02 immutable sushiRouter;

  constructor(address _factory, address _uniRouter, address _sushiRouter) public {
    factory = _factory;  
    sushiRouter = IUniswapV2Router02(_sushiRouter);

  function uniswapV2Call(address _sender, uint _amount0, uint _amount1, bytes calldata _data) external {
      address[] memory path = new address[](2);
      uint amountToken = _amount0 == 0 ? _amount1 : _amount0;
      address token0 = IUniswapV2Pair(msg.sender).token0();
      address token1 = IUniswapV2Pair(msg.sender).token1();

      require(msg.sender == UniswapV2Library.pairFor(factory, token0, token1), "Unauthorized"); 
      require(_amount0 == 0 || _amount1 == 0);

      path[0] = _amount0 == 0 ? token1 : token0;
      path[1] = _amount0 == 0 ? token0 : token1;

      IERC20 token = IERC20(_amount0 == 0 ? token1 : token0);
      token.approve(address(sushiRouter), amountToken);

      // no need for require() check, if amount required is not sent sushiRouter will revert
      uint amountRequired = UniswapV2Library.getAmountsIn(factory, amountToken, path)[0];
      uint amountReceived = sushiRouter.swapExactTokensForTokens(amountToken, amountRequired, path, msg.sender, deadline)[1];

      token.transfer(_sender, amountReceived - amountRequired);

If there is any profit, we send it to the address which initiated the transaction ( _sender ), who is us!


Discussion and Key Takeaways

  • The authors created an open-source smart contract that operates arbitrages between Sushiswap and Uniswapis. The program is written in Node.js using the Ethers.js library and incorporating an Infura endpoint. The arbitrage smart contract is written in Solidity.

  • After following this tutorial, users are able to create a working example of an Infura based flash loan arbitrage bot.

Implications and Follow-ups

  • Arbitrage, contract coding and optimistic transfer come together to create an impressive new tool. It’s an innovation built on top of the innovation of public blockchains. The two innovations compound each other, creating a truly powerful and unique mechanism.


  • For a pairing as common as ETH and Dai, there are not many profitable opportunities. These are high volume pairs (many people using them) and Uniswap and Sushiswap are relatively popular exchanges. In economic terms, arbitrage opportunities result from market inefficiencies. If many people are using these pairs, we are unlikely to find many opportunities. We must find newer tokens or exchanges!
1 Like

@stayhungry07212 - Dimitar, thanks so much for contributing this to SCRF, and welcome! Next time you might want to check out our Post Ideas category. We often award research summary grants to summary proposals that meet our standards.

@Jerry_Ho this might be of interest to you… I’d be interested in your feedback

Hi, @jmcgirk, thank you for your feedback.
It was my very first article in the forum.
Yeah, I didn’t know there’s a pipeline here and the Post Ideas section.
I will take a look at it.

1 Like