Skip to content

This repo is a live and currently in development. It is the process of me creating an ethereum arb bot

Notifications You must be signed in to change notification settings

SebMelendez01/0xpastaman-arb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 

Repository files navigation

0xpastaman-bot Overview

The goal of this project was to better understand the world of MEV specific arbitrage. This bot is not made to be put into production and compete in Arb opportunities.

Now that we are past a disclaimer, lets get into it. This bot focuses on off-chain simulation for uniswap_v2 specifically solving the convex optimization problem of CFMMs. In order to compute if there is an opportunity two streams are set up, a MempoolStream and a DexStream, on a sub-process. Every time the reserve data is updated, i.e. Sync(uint112,uint112) event is detected, the main process computes if there is an opportunity.

The TokenStream is currently being fazed out for a more scalable MempoolStream. The currently file for executing is bot/execute.py

Current Problems

I have set up a mempool scraper but the transactions I am scraping are old and the pools that I am decoding from the mempool only have a single transaction. I need to get more up to date transactions from my mempool scraper. There may also be a blocking problem with how python works and setting up a aioQueue essentially a pipe. .coro_get() blocks as well as the websocket.[TO DO LOOK INTO and see if it is a problem.] Can set up a system test of and see if on of the aync streams is getting blocked.

Current Vunerablities

The bot currently does not take into account "poison tokens." Currently the transaction profit is not simulated on chain and therefore the bot risks submitting transactions to the network that will not be or were never valid. This can be fixed with the flashbots code by only calling coinbase.transfer if the transaction was profitable and everything succeeded.

Future Work and Next Steps

Scaleing Option (CEX)

One way to scale is to do a little bit of upfront work and for a specific API/oracle get all of the tokens that can be queried for a specific price, then find all of the ERC20 addresses. Then use the factory address in order to get all of the viable pools. We can then create all of DEXs add the DEXs to the DEX stream and then we are able to ensure that each token price can be queried. This is less dynamic work and is more upfront. This would also create a significantly larger number of DEX's to run the simulation on and many of the pools we would be looking at would not actually contribute to finding an Arbitrage.

Scaling Option (MEMPOOL and CEX/Price Feed)

CoinGeckoAPI

Updating the Framework: In order to scale the DexStream and TokenStream effeciently we need to dynaically get Dex's from the Mempool. We can do this by using a filter to look specifically for any transaction that interacts with the UniswapV2Router. We can then take the path function param and find all the paths that people are swaping through but calling the FactoryV2 contract. We can then check if the token price exists on some API service, if it does we can add the tokens to both the DexStream and TokenStream.

Note: CoingeckoAPI doesn't allow me to get all to coins that I want. Need to figure out another solution. Instead of CoinGecko look into ANKR

The bot currently does not scrape/listen to the mempool for DEX's/Tokens to add to the DexStream and TokenStream. The goal is to instead of using Coinbase API to get the token prices use CoinGeckoAPI as you can send the token address rather that the Ticker Symbol of the token. This will be more effecient and allow for the ability to get DEXs and tokens based on addresses rather than keeping a database to switch. If we are to use the CoinGeckoAPI although it would allow for us to get price data based on address we would need to poll for the data. Best way to do that is instead of set up a stream, every time reserves are updated we quickly request for all token prices async. If I go ahead with this I can turn the token stream into the Mempool stream.

The issue with not constantly checking the price is that arbs can be created from a change in reserve amount on a dex but also a change in the token price on a CEX. By only getting price data when reserves changes we miss an opportunity.

MORALIS (CURRENT SOLUTION)

This API allows me to query based on token address nearly any ERC20 token. It would be reliant on someone elses system but it would allow me to have a finished product and scalable system much faster.

payload = {
    "tokens": [
        {
            "token_address": "0xae7ab96520de3a18e5e111b5eaab095312d7fe84",
        }
    ]
}
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "X-API-Key": "API-KEY"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)

Use the moralis API and update the token price whenever the reserves are updated for the tokens in that dex.

The issue with this is I am completely reliant on another technology for token price updates that do not seem to be the most accurrate and from a real time feed. Example is ETH has been staying at a price of $1616.03 which is off the price the actual price of 2 dollars. The data is said to be being pulled from UniV3 so this is possible and not out of the range of possibility but something to note. The price feeds may not be real time.

Scaling Option (MEMPOOL and DEX)

The final option is to instead of update the token price data from a centralized source we do it from the DEX data, everytime a pools reserve price is updated we would update the price data for those 2 tokens. This would make the price data significantly more volitile and we would want to run it through a Kalman filter as the price of a token should be somewhere around the range of all of the token prices every time they are updated. Assuming markets have some sort of effeciency.

To get the price of a token I may be able to use this and update it every time a tokens comes in. The issue is I wouldn't be able to calculate the pruce until I have 2 Transactions in the pool. I would need to create a staging and a final. This may also be good because it would limit the DEXs that I look at to only ones with more that 2 transactions. I can remove DEXs from the Stageing area every n seconds if another transaction as not come in, this would be a sort of built in filter for pools trading more volume: https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles

Current implemenation

Pools are required to be build by the user. This is not scalable and as more code is added this will be fixed. The currently contract implementation is only golfed AAVE flashloan calls. Uniswap FlashCall is also another option. We are also currently only looking at UniV2

NOTES:

This repo is in developement and therefore this project is currently not made to be cloned as well as the readme is a culmination of notekeeping and thought process.

Useful Routing Problem Links

Python Example
Paper
Julia Example

YUL Hacks

Advanced Solidity

To Do

  • Flashbots/submit to builder
  • Successful submission to flashbots only if the opportunity is profitable (costs more gas)
  • JUMPI for execution path instead of switch selector
  • Golfed swap code
  • A way to save the swap code calldata for when the contract is called back sstore2 Lib

Building Call Data

Initiate Falshloan Calldata

0x7b5C526B7F8dfdff278b4a3e045083FBA4028790
0x0      0xab9c4b5d
0x0      000000000000000000000000[9d7f74d0c41e726ec95884e0e97fa6129e3b5e99]      Receiver
0x20     00000000000000000000000000000000000000000000000000000000000000e0        Token Array Location
0x40     0000000000000000000000000000000000000000000000000000000000000120        Amounts Array Location
0x60     0000000000000000000000000000000000000000000000000000000000000160        Modes Array Location
0x80     000000000000000000000000[9d7f74d0c41e726ec95884e0e97fa6129e3b5e99]      OnBehalfOf
0xA0     00000000000000000000000000000000000000000000000000000000000001a0        Params Location
0xC0     0000000000000000000000000000000000000000000000000000000000000000        Referral Code

0xE0     0000000000000000000000000000000000000000000000000000000000000001        Token Array Length
0x100    00000000000000000000000065afadd39029741b3b8f0756952c74678c9cec93        Token[0]
0x120    0000000000000000000000000000000000000000000000000000000000000001        Amounts Array length
0x140    0000000000000000000000000000000000000000000000000000000000989680        Amount[0]
0x160    0000000000000000000000000000000000000000000000000000000000000001        Modes Array Length
0x180    0000000000000000000000000000000000000000000000000000000000000000        Modes[0]
0x1A0    0000000000000000000000000000000000000000000000000000000000000000        Params

Amounts Array Location = Token Array Location + [0x20 + 0x20 * (Token Array Length)]
Modes Array Location = Amounts Array Location + [0x20 + 0x20 * (Amounts Array Length)]
Params Location = Modes Array Location + [0x20 + 0x20 * (Modes Array Length)]

Helpful Testing links

Alchemy Faucet
Quicknode Faucet
Ethereum Gas Opcodes
Decompile Contracts
Gas Savings Tips
SStore 2
Is Zero Gas Savings
Sandwich Bot
Get Amount Out
Get Pair
Flashloan Pool
TEST
Uniswap Deployment Addresses
Defi liq. Monotoring

CFMM zero to one
L1 L2 Hueristics
CFMM Routing
Julia Routing Library
Python Routing Example - angeris
Flashbots Convex Opt.
Python CFMM Example
Mathmatical Opt. DEXs\

All about Assembly
All amout Memory
All about Calldata
Deconstructing Sol Contract
Hashing Strings\

First Key to building MEV bots
MEV Arb Bot
How I built an arb bot\

Ideas

Zero MEV\

  1. Create the oppotunity by looking through the mempool and building a bundle that creates a larger arb opportunity

About

This repo is a live and currently in development. It is the process of me creating an ethereum arb bot

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published