๐ for more details, check my mirror post about this tool.
- WETH/DAI
- Uniswap (0xa478c2975ab1ea89e8196811f51a7b7ade33eb11)
- Sushiswap (0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f)
- Shebaswap (0x8faf958e36c6970497386118030e6297fff8d275)
- Sakeswap (0x2ad95483ac838e2884563ad278e933fba96bc242)
- Croswap (0x60a26d69263ef43e9a68964ba141263f19d71d51)
Add your Alchemy API key and endpoint to a file named .env
:
cp .env_example .env
vim .env
Create a virtual environment:
virtualenv venv
source venv/bin/activate
Install dependencies:
make install_deps
Install the CLI:
make install
You can run the CLI with:
bdex
We leverage Alchemy's API endpoint eth_blockNumber_hex
to get the latest block:
bdex -c
๐ก The block number can be checked against ETHstat.
๐ก We are crafting the checksum address string by hand without directly Keccak-256 hashing the methods and parameters.
We leverage Alchemy API endpoint eth_call
to retrieve the current token balance for a specific exchange:
bdex -b TOKEN EXCHANGE
We loop over the previous method for a list of tokens and exchanges:
bdex -a
To be able to compare our results from the previous steps, we implemented an alternative way to fetch pair balances utilizing the Python web3 library:
bdex -w
๐ก For this library, it's necessary to supply the contracts' ABI (in our case, for DAI and WETH, located at ./docs
)
๐ก A third option to verify token balances is through Etherscan tokenholdings dashboard.
To get the current price for WETH/DAI
in all exchanges (e.g., as shown in the projects' dashboards), run:
bdex -p QUANTITY TOKEN1 TOKEN2
Quote for trading 1 WETH
:
Quote for trading 10 WETH
:
Quote for trading 100 WETH
:
An AMM replaces the buy and sell orders in an order book market with a liquidity pool of two assets, both valued relative to each other. As one asset is traded for the other, the relative prices of the two assets shift, and the new market rate for both is determined.
The constant product is:
token_a_pool_size * token_b_pool_size = constant_product
All the exchanges are forks from UniswapV2, so they all use the same price formula for trading:
market_price_token1 = token2_balance / token1_balance
For example, in a pool with 2,000,000 DAI
and 1,000 WETH
, the constant product is 2,000,000,000
and the market price for WETH
is $2,000
.
To find the buy price for a certain quantity, first, we calculate how much WETH
needs to remain in balance to keep the constant product unchanged:
token1_balance_buy = constant_product / (token2_balance + quantity)
Then we calculate how much WETH
goes out to keep this constant:
t1_amount_out_buy = token1_balance - token1_balance_buy
The buy price to reflect this ratio is:
buy_price = quantity / t1_amount_out_buy
To find how much we can sell a certain quantity of WETH
for DAI
, first, we calculate the ratio of DAI
in the new pool, as we add WETH
:
token2_balance_buy = constant_product / (token1_balance + quantity)
We then calculate how much DAI
will go out:
t2_amount_out_buy = token2_balance + token2_balance_buy
We calculate the DAI
balance reflected with the income WETH
:
token1_balance_sell = constant_product / (token2_balance - quantity)
And what's the proportion of WETH
in the new balance:
t1_amount_in_sell = token1_balance + token1_balance_sell
We can now calculate the sell price to reflect the balance change, keeping the constant:
sell_price = t2_amount_out_buy / t1_amount_in_sell
Run an algorithm to search for arbitrage in the supported exchanges for a certain buy quantity:
bdex -x QUANTITY
Arbitrage opportunities for 10 WETH
:
Arbitrage opportunities for 1 WETH
:
Arbitrage opportunities for 0.01 WETH
:
To run the arbitrage algorithm for a certain amount of minutes:
bdex -r MIN
Results are saved into results/<arbitrage_TIMESTAMP>.txt
.
Here is a sample of the results running this algorithm for 100 minutes for trading 1 WETH
:
{'buy_exchange': 'SUSHISWAP', 'sell_exchange': 'UNISWAP', 'arbitrage': '7.01', 'buy_price': 3475.14, 'sell_price': 3482.15}
{'buy_exchange': 'SUSHISWAP', 'sell_exchange': 'SHEBASWAP', 'arbitrage': '4.27', 'buy_price': 3475.14, 'sell_price': 3479.41}
{'buy_exchange': 'SHEBASWAP', 'sell_exchange': 'UNISWAP', 'arbitrage': '2.06', 'buy_price': 3480.09, 'sell_price': 3482.15}
{'buy_exchange': 'CROSWAP', 'sell_exchange': 'UNISWAP', 'arbitrage': '13.06', 'buy_price': 3469.09, 'sell_price': 3482.15}
{'buy_exchange': 'CROSWAP', 'sell_exchange': 'SUSHISWAP', 'arbitrage': '5.79', 'buy_price': 3469.09, 'sell_price': 3474.88}
{'buy_exchange': 'CROSWAP', 'sell_exchange': 'SHEBASWAP', 'arbitrage': '10.32', 'buy_price': 3469.09, 'sell_price': 3479.41}
...
To run the algorithm in a separated container, first install Docker, then build the Docker image:
docker build -t bdex .
Finally, run the container (in a separate terminal tab):
docker run -v $(pwd):/results -it bdex sleep infinity
Results are available at results/<arbitrage_TIMESTAMP>.txt
.
๐ก You can inspect your container at any time with these commands:
docker ps
docker exec -it <container_id> /bin/bash
docker inspect bdex
Cleaning up:
docker volumes prune
Install dependencies (in a virtual env):
make install
Useful commands:
make lint
make test