Maker Protocol Technical Docs
  • MakerDAO Technical Docs
  • Getting Started
    • Maker Protocol 101
  • Smart Contract Modules
    • Dai Module
      • Dai - Detailed Documentation
    • Core Module
      • Vat - Detailed Documentation
      • Spot - Detailed Documentation
    • Collateral Module
      • Join - Detailed Documentation
    • Liquidation 2.0 Module
    • System Stabilizer Module
      • Flapper - Detailed Documentation
      • Flopper - Detailed Documentation
      • Vow - Detailed Documentation
    • Oracle Module
      • Oracle Security Module (OSM) - Detailed Documentation
      • Median - Detailed Documentation
    • MKR Module
    • Governance Module
      • Spell - Detailed Documentation
      • Pause - Detailed Documentation
      • Chief - Detailed Documentation
    • Rates Module
      • Pot - Detailed Documentation
      • Jug - Detailed Documentation
    • Proxy Module
      • Proxy Actions - Detailed Documentation
      • Vote Proxy - Detailed Documentation
      • CDP Manager - Detailed Documentation
      • DSR Manager - Detailed Documentation
    • Flash Mint Module
    • Maker Protocol Emergency Shutdown
      • Emergency Shutdown for Partners
      • The Emergency Shutdown Process for Multi-Collateral Dai (MCD)
      • End - Detailed Documentation
      • ESM - Detailed Documentation
  • Glossary
    • MCD Glossaries
    • Smart Contract Annotations
  • Deployment Addresses
    • Maker Protocol Deployments
  • Security
    • Security for the Maker Protocol
  • Building on top of the Maker Protocol
    • Developer Guides and Tutorials
    • The Dai Javascript Library of the Maker Protocol
      • Getting started
      • Configuration
        • Plugins
      • Vault manager
      • Collateral types
      • Dai Savings Rate
      • Currency units
      • System data
      • Advanced
        • Transaction manager
        • DSProxy
        • Events
        • Using multiple accounts
        • Adding a new service
      • Single-Collateral Sai
        • Collateralized Debt Position
        • CDP Service
        • Price Service
        • System Status
        • Tokens
        • Token Conversion
        • Exchange Service
    • Pymaker
  • Keepers
    • The Auctions of the Maker Protocol
    • Auction Keepers
      • Auction Keeper Bot Setup Guide
    • Market Maker Keepers
      • Market Maker Keeper Bot Setup Guide
    • Cage Keeper
    • Simple Arbitrage Keeper
    • Chief Keeper
  • Command-line Interfaces
    • Seth
    • Multi Collateral Dai (MCD) CLI
    • Dai and Collateral Redemption during Emergency Shutdown
    • Emergency Shutdown (ES) CLI
  • Miscellaneous
    • Liquidations 1.2 System (Deprecated)
      • Cat - Detailed Documentation
      • Flipper - Detailed Documentation
    • SCD <> MCD Migration
    • Upgrading to Multi-Collateral Dai Guide
Powered by GitBook
On this page
  • Overview
  • Learning objectives
  • Pre-requisites
  • Guide
  • Troubleshooting
  • Next steps
  • Resources
Export as PDF
  1. Keepers

Simple Arbitrage Keeper

PreviousCage KeeperNextChief Keeper

Last updated 5 years ago

Overview

Typically in the form of an automated bot, Keepers are external actors that participate in , , , and system upkeep within the Maker protocol and the greater Ethereum ecosystem. Under a pure economic assumption, they are solely incentivized by profits or a vested interest. However, their activity provides indirect services such as increased liquidity and price consistency across various financial markets. This guide presents a simple arbitrage keeper, and structure thereof, that can be used out of the box to participate in wildly volatile markets. The purpose of the guide is to motivate the user in improving its functionality to participate in less volatile markets, leading to a more efficient financial ecosystem.

Learning objectives

By reading this guide, you’ll gain:

  • Better understanding of Arbitrage, how it is achieved and the role it plays in financial markets

  • An overview of the simple arbitrage keeper and common structure across the Maker Keeper framework

  • Insight into the operation of the simple arbitrage keeper and ways to improve its code

Pre-requisites

  • At least Python 3.6.2 and some python experience

  • Linux, macOS, or Cygwin (on Windows)

  • Some general experience with Ethereum Development (account management, contract interaction, node hosting)

Guide

Introduction to Arbitrage

Arbitrage is the process of simultaneously purchasing an asset on one exchange and selling a similar, if not identical, asset on another exchange at a higher price. Conceptually, this trading strategy can be broken down into two legs, the first buying leg and the second selling leg. As the timestamp of these legs converge, the risk of asset exposure approaches zero. For example, if both trades are not executed in perfect synchrony, there is a chance that the second trade is completed by another actor, forcing the arbitrageur to hold an asset until another opportunity arises.

System Process Structure

Operation of the Simple Arbitrage Keeper

The step for each process in simple-arbitrage-keeper is as follows:

  1. Keeper Entry -> enter into SimpleArbitrageKeeper class

  2. Startup -> make all necessary approvals between tokens, exchanges, and tx-manager

  3. Evaluate Market -> pull price data from Oasis REST API and Uniswap exchange contracts

  4. Profitable Opportunity Found? ->check if profit opportunity exists with a given max engagement and min profit

  5. Execute multi-step trade -> with use of TxManager, buy asset on exchange A and sell on exchange B within one Ethereum transaction

Documentation

Startup on Kovan

To operate the keeper, call the /bin/simple-arbitrage-keeper script with the required arguments. This adds the pyexchange and pymaker modules to the python path and initializes the SimpleArbitrageKeeper class. It's convenient to write a shell script that can be easily rerun after argument changes, but before we begin, let's prepare our Keeper ethereum address, deploy our TxManager, find the Uniswap exchange addresses and MatchingMarket address.

Keeper Installation

This project uses Python 3.6.2. In order to clone the project and install required third-party packages please execute:

$ git clone https://github.com/makerdao/simple-arbitrage-keeper.git
$ cd simple-arbitrage-keeper
$ git submodule update --init --recursive
$ pip3 install -r requirements.txt

Install the DappHub Toolkit

If you are running Linux or macOS you can take advantage of our all in one installer.

$ curl https://dapp.tools/install | sh

Keeper Ethereum Address

Deploy TxManager

$ git clone https://github.com/makerdao/tx-manager.git
$ cd tx-manager
$ dapp update
$ dapp --use solc:0.4.25 build --extract

$ export SETH_CHAIN=kovan
$ export ETH_FROM=<your Keeper Ethereum Address e.g. 0xABC>
$ export ETH_GAS=2000000
$ dapp create TxManager --password /path/to/passphraseOfAddress.txt

The output of dapp create is the address to your TxManager

Deploy/Find a parity node

Uniswap Exchange Addresses

Shell Script

As was mentioned before, let's make a shell script so that it's easy to run this Bot. For example, we're using Kovan Sai for the entry-token since we won't be exposed to the arb token's price exposure in between trades. Moreover, for kovan testing, we will be using the WETH/DAI pair, since liquidity is thin across the Kovan versions of MatchingMarket and Uniswap exchanges. Any NoneType errors are likely due to a lack of liquidity on either exchange and can be resolved once liquidity is added. As mentioned earlier, the min-profit and max-engagement arguments define how the keeper will operate. Maximum engagement refers to the amount of entry-tokens you would like to sell within the first leg of the trade, whereas minimum profit refers to the amount of profit gained from executing the arbitrage; both arguments are denominated in entry-tokens and in units of ether (in the below script, 1 SAI of min-profit would be 1 SAI). For example, the below script will trade with a max-engagement of 10 SAI, but only if the returned value from the trade results in at least 11 SAI.

Create a file called like below, insert the arguments relevant to your environment, make it executable, then run it!

$ vim run-simple-keeper-kovan.sh

In your run-simple-keeper-kovan.sh file:

#!/bin/bash
/full/path/to/githubClone/simple-arbitrage-keeper/bin/simple-arbitrage-keeper \
	--rpc-host 'kovan.sampleparitynode.com' \
	--eth-from '0xABC' \
	--eth-key 'key_file=/path/to/keystore.file,pass_file=/path/to/passphrase.txt' \
	--uniswap-entry-exchange '0x47D4Af3BBaEC0dE4dba5F44ae8Ed2761977D32d6' \
	--uniswap-arb-exchange '0x1D79BcC198281C5F9B52bf24F671437BaDd3a688' \
	--oasis-address '0x4A6bC4e803c62081ffEbCc8d227B5a87a58f1F8F' \
	--oasis-api-endpoint 'https://kovan-api.oasisdex.com' \
	--tx-manager '0xABC' \
	--entry-token '0xC4375B7De8af5a38a93548eb8453a498222C4fF2' \
	--arb-token '0xd0A1E359811322d97991E03f863a0C30C2cF029C' \
	--arb-token-name 'WETH' \
	--min-profit 1 \
	--max-engagement 10 \

Make your Keeper executable, and run it!

$ chmod +x run-simple-keeper-kovan.sh
$ ./run-simple-keeper-kovan.sh

Initial Startup

During the initial startup, several approval transactions will be sent to the tx-manager, and relevant exchanges. When complete, you'll see a “Watching for new blocks” message that indicates that the bot is now looping through the lifecycle.process_block() method; following that message and with every new block is a "Best Trade regardless of profit" message that acts as a "heartbeat" to the Keeper.

Kentons-Macbook:scripts kentonprescott$ ./run-simple-arbitrage-keeper-mainnet-XYZ-XYZ.sh
2019-10-19 17:21:57,463 INFO     Keeper connected to RPC connection https://...
2019-10-19 17:21:57,463 INFO     Keeper operating as 0xABCD
2019-10-19 17:21:58,523 INFO     Executing keeper startup logic
2019-10-19 17:22:04,820 INFO     Watching for new blocks
2019-10-19 17:22:13,983 INFO     Best trade regardless of profit/min-profit: -1.243077085275947008 DAI from Uniswap to Oasis

Nominal Operation

After the initial approval phase the Keeper's startup will look something like the below output and will continue to print "Best Trade ... " messages with every new block witnessed. When the keeper publishes a transaction, all relevant info will be logged and printed to the console. Finally, when you’d like to shut down the keeper, simply click CTRL-C, and it will gracefully shutdown.

Troubleshooting

During keeper operation, if the following error is shown, just CTRL-C and rerun:

ValueError: {'code': -32010, 'message': 'Transaction with the same hash was already imported.'}

Next steps

Improvements

Here are some suggestions to improve the usability, versatility, and profitability of this keeper. We hope that everyone tinkers with the parameters, runs the keeper for their own benefit, and eventually upgrades the bot to meet their risk tolerance and profit appetite.

  • Develop unit tests for each method

  • Use the Uniswap Factory contract to query the uniswap-entry-exchange and uniswap-arb-exchange addresses rather than requiring it as an argument

  • Increase scope

    • Monitor more than one pair

    • Monitor more than two decentralized exchanges

    • Implement support for centralized exchanges

    • Increase number of intermediary arb tokens

      • (e.x. DAI → WETH → BAT → DAI)

  • Improve efficiency of TxManager

    • Do we really need to send all of our token balance to the contract during every atomic transaction?

  • Read the state of the MatchingMarket (OasisDex) contract rather than using the Oasis REST API

  • Send trade updates through a text/email Python API

Resources

With advancement in technology, this trading strategy is typically automated and can detect, as well as, profit from price deviations in a matter or seconds. Arbitrage opportunities exist because of , such as a temporary shortage of liquidity. As a result, arbitrage provides a mechanism to ensure prices on one exchange/market do not deviate far from the .

The is an arbitrage keeper for OasisDex and Uniswap. Given a minimum profit per trade and maximum trade size, as defined by the user and in units of entry_token, the Keeper will scan for arbitrage opportunities. When running, it monitors the arb_token/entry_token price on both exchanges, and when a discrepancy is detected, it executes an atomic multi-step trade in a single Ethereum transaction. The multi-step trade is made up of two legs: the first leg is the purchasing of arb_token with the entry_token on the start_exchange, while the second leg is the selling of the arb_token with the entry_token on the end_exchange. The type of entry_token and arb_token is typically of a stable and volatile type, respectively; since arbitrage opportunities can be scarce, the Keeper sometimes rests in a default state, holding the entry_token for extended periods of time as it looks for new opportunities. Exposure only to a stable token is especially important in this default state. If any leg of the trade fails, the entire trade reverts, thereby upholding the "risk-free" attribute of true arbitrage.

It inherits a system structure that is consistent with other keepers in the Maker Keeper Framework. Apart from libraries typical to python projects, it relies on and , both of which are highly applicable Python APIs for the Maker Protocol Contracts and cryptocurrency exchanges, respectively. As can be seen in the flowchart, the ‘Lifecycle box’ is a that helps define the proper life cycle of a keeper; it consists of keeper startup, timers and/or subscriptions to Web3 events, and a keeper shutdown phase. The ‘Process block’ box is executed when the Keeper's node receives a new block. It generally contains the logic to query the blockchain state, evaluate any profit opportunities, and when applicable, publish a transaction.

General high level information and comments for each class/method are in the .

The usage of the bot can be found in the of the README. Here are some preparation steps in running on Kovan:

For some known Ubuntu and macOS issues see the .

If you're having issues with installation, head over to the

Your Keeper will publish transactions through this address. Your ethereum address needs to be accessible by , in order to deploy TxManager through . Furthermore, when the Keeper is deployed and in operation, this address must contain some ETH for transaction costs as well as an amount of entry-tokens equal to the max-engagement set by the User. Follow to ensure seth can see your keystore and passphrase files.

If you'd like to start from scratch, and use geth account new, to create a new account, set a passphrase, and place the passphrase into a <address>.txt file in the ~/Library/Ethereum/passphrase/ directory; the corresponding keystore file can be found in the ~/Library/Ethereum/keystore/ directory. Both the keystore and passphrase files will later be passed into the Keeper as an argument. Make a note of your Keeper Ethereum Address, its keystore file location and passphrase file location.

A must be deployed and linked with the Keeper ethereum address in order to bundle multiple contract calls in a single ethereum transaction; this is what we call an atomic transaction, where the entire call set is successful, or the state remains unaffected. Once the DappHub Toolkit is installed, execute the following commands to deploy TxManager:

You need access to a JSON-RPC host that’s connected to a parity node. Unfortunately, Infura APIs are not connected to parity nodes, so you will need to find access to a remote endpoint (one example is ) or run a node on your local machine. An example of a remote node could be

You'll need to find the address to the Uniswap exchange corresponding to the entry-token as well as arb-token. To do that, call the getExchange(TokenAddress) at the Uniswap Factory contract to query the exchange addresses. . For example, you can use the Kovan WETH token address and call getExchange(0xd0A1E359811322d97991E03f863a0C30C2cF029C)

Rather than the default gas price implement a

To save gas, and by ID rather than use MatchingMarket.offer(...) and the on-chain matching engine

market making
auctions
market arbitrage
market inefficiencies
fair value
1
simple-arbitrage-keeper
pymaker
pyexchange
pymaker utility class
simple-arbitrage-keeper github repository
Usage section
pymaker README
'Manual Installation' section
seth
dapp.tools
these instructions
install geth
TxManager
https://rivet.cloud/
https://kovan.sampleparitynode.com:8545
You can do that here
dynamic gas price strategy
https://math.stackexchange.com/a/94420
https://www.dailycodingproblem.com/blog/how-to-find-arbitrage-opportunities-in-python/
get all active orders
take specific orders
https://github.com/makerdao/market-maker-keeper
https://github.com/makerdao/arbitrage-keeper
https://github.com/makerdao/tx-manager
https://github.com/makerdao/pymaker
https://github.com/makerdao/pyexchange