Feb 16, 2023
mev
rust

Improve liquidation bots with price update predictions 1/2

dark-forest

Implementing a competitive liquidation bot is a long run. It requires a deep understanding of all variables in place, and nights spent with your friend tweaking efficient algorithms and crunching lending protocols' smart contracts.

Users' health-factor is the key variable you should track in this business. When the HF drops below 1.0, you are given the chance to liquidate.

Sounds simple right? Not at all, there's an army of optimized bots out there, making this game a kind of "natural selection". There are many factors making a bot fast in this context. In this blog post I'm going to explain some of them.

Health factor

A user's HF is expressed as the ratio between the "total collateral value" and the "total debt value". Such values are expressed in terms of a base currency dictated by the protocol (i.e. AAVE v2 uses ETH, while AAVE v3 uses USD). For details about HF logics and math I suggest going through this excellent article: An Empirical Study of DeFi Liquidations: Incentives, Risks, and Instabilities.

A good liquidation bot MUST track the HF with surgical precision and this relates to 2 aspects:

  • Price oracles: Listen to price oracles' feeds to update user positions in memory, and recompute the HF. This is the first driver leading HFs below the 1.0 threshold.
  • Accrued interests: User debts accrue interests block by block. Your bot should mimic the on-chain math of the target protocol. Maybe I'll describe this process in another post.

Price oracles

Lot of DeFi protocols are directly integrated to ChainLink off-chain oracles.

It has a decentralized network that computes asset prices off-chain. The network evetually reaches consensus on an asset price, then pushes a transaction on-chain to update it. The new price is stored inside a ChainLink aggregator smart contract connected to other DeFi protocols via proxy based mechanisms. An aggregator smart contract exists for each asset.

When the price is updated, the contract emits an event of the form:

// AggregatorInterface.sol

// The value of 'current' describes the current value of the asset
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);

😎 Backrunning

Ok little Johnny, I know you feel smart and think that subscribing to price change events is a good idea. After all why not? As long as you stay connected to a websocket your bot will be super fast...

If you go this way, soon or later you will ask yourself:

Why my liquidation txn fails? Why the on-chain HF is above 1.0 but I have 0.9 locally? Code is correct, I have a fast connection, I don't understand..

The answer is: Someone else liquidated the user in the same block the price changed! 🤬🤬🤬

Substantially there are bots listening for price update transactions in the mempool. These bots are able to spot liquidation opportunities in advance: 6-7 seconds before the new price is written in a block. Adjusting the gas price they are able to push a transaction right after the price update (that's why "backrunning").

I will show you the source code for doing this in the next part of this blog.

For now keep calm and breathe deep, we are entering into the dark forest.

Part 2

Credits

Forest image by Ilya Nazarov via Tolkienpedia.