Skip to content
This repository has been archived by the owner on Dec 9, 2024. It is now read-only.

An example bot demonstrating OEV extraction using API3 OEV network

License

Notifications You must be signed in to change notification settings

api3dao/oev-orbit-bot-example

Repository files navigation

OEV Orbit Bot Example

This repository contains an example OEV Searcher bot implementation targeting Orbit Lending. To understand how OEV works, visit the OEV documentation.

Before running this application, be sure to read and understand the code.

Process Overview

The OEV bot follows this flow to extract OEV from Orbit Lending:

  1. Initialisation
  • Get log events from the Blast chain and build a list of accounts to watch for possible liquidation opportunities
  • Get log events from the OEV Network to determine awarded/live/lost bids
  1. Main Loop
  • Continuously watch log events from Orbit to maintain a list of accounts to watch
  • Attempt liquidations when opportunities are detected

Opportunity Detection and Value Extraction - In Depth

Given a list of accounts to watch, the app does the following: (Refer to findOevLiquidation())

Search for an OEV Liquidation Opportunity

  • Simulate liquidation potential by transmuting the oracle's value for a feed

    • Refer to the Transmutation section of this README for more information.
    • Find Orbit's Price Oracle: orbitSpaceStation.oracle()
      • Read the current value of the oracle for the target feed: priceOracle.getUnderlyingPrice(oEtherV2)
    • Apply a transmutation value to the read price: getPercentageValue(currentEthUsdPrice, 100.2)
    • Create a set of calls that can be used to transmute the value of the oracle temporarily
      • Set the dAPI Name to a beacon we control: api3ServerV1Interface.encodeFunctionData('setDapiName', [dapiName, beaconId])
      • Set the value of the target beacon to our transmuted value: updateBeaconWithSignedData
    • In a single call, apply the transmutation call data and retrieve account liquidity for all accounts
  • For all accounts assessed using a transmuted oracle value sort by the biggest shortfall.

  • For all shortfall accounts, re-simulate the transmutation call, simulate a liquidation and determine the profit.

  • Find the most profitable liquidation (using ETH and USD components).

  • At this point, the OEV bidding process begins. To understand the OEV bidding lifecycle refer to these OEV docs

    • Bid on an update for the feed

      const bidDetails: BidDetails = {
        oevProxyAddress: contractAddresses.api3OevEthUsdProxy,
        conditionType: BID_CONDITION.GTE,
        conditionValue: transmutationValue,
        updateSenderAddress: contractAddresses.multicall3,
        nonce,
      };
  • Store the active bid's parameters

Attempt to Capture the OEV Liquidation Opportunity

Refer to attemptLiquidation(). See the OEV Network docs for more information.

  • Listen for the award, expiry or loss of the active bid
  • If the bid is awarded, encode a multicall transaction containing
    • Call #1: Call to the API3 Server with the awarded bid details as call data with value corresponding to the bid amount
    • Call #2: Call the Orbit Ether Liquidator contract with the liquidation parameters
  • Simulate the liquidation multicall and determine the profitability - bail if the profit is below the minimum
  • Execute the liquidation transaction
  • Report the fulfillment on the OEV Network

Transmutation

In order to bid on an OEV update an application will need to determine the bid's parameters, and in particular:

  • The value of the bid (what will be paid for the bid in the Blast chain's native token)
  • The conditions under which the bid will be considered (less-than or greater-than a specific dAPI value)

Determining these values would generally require re-implementing the business logic of the dApp being targeted, something which is often very onerous. To make target dApp integration easier, API3 has built a contract that facilitates the "transmutation" of a dAPI (from the concept of transmuting silver to gold).

Purpose of Transmutation:

  • Simulating Price Changes: By transmuting the value of a data feed, we can simulate how changes in the price would affect account liquidity. This helps in identifying liquidation opportunities without altering the actual market conditions.
  • Efficient Testing: It allows for the efficient testing of various scenarios to find the most profitable liquidation opportunities.
  • Non-Intrusive: This process is non-intrusive and does not affect the actual state of the blockchain since it's done within a simulated environment.

The contract's relevant function is quoted below:

/// @notice eth_call'ed while impersonating address-zero with zero gas
/// price to simulate an external call
/// @param target Target address of the external call
/// @param data Calldata of the external call
/// @return Returndata of the external call
    function functionCall(
        address target,
        bytes memory data
    ) external override returns (bytes memory) {
        require(msg.sender == address(0), "Sender address not zero");
        require(tx.gasprice == 0, "Tx gas price not zero");
        return Address.functionCall(target, data);
    }

See the full ExternalMulticallSimulator contract implementation here.

This function can only be called with a signer address of zero, valid only for non-write operations like a simulated RPC contract call. This can be executed via the eth_call RPC method. The deployed contract instance has the DAPI_NAME_SETTER_ROLE on the Api3ServerV1, allowing it to change the datafeed a dAPI name points to in a non-writing and/or simulated transaction.

Within a simulated contract call, the app can:

  1. Create and Sign a new Datafeed data point:

  2. Simulate the Multicall Transaction:

    • Use the data feed update created earlier to initialize a datafeed our app controls, with a specified value (e.g. the current target data feed's value + 1%).
    • Set the target datafeed of the dApp's dAPI to the newly-initialized datafeed.
    • Read the necessary functions on the target dApp to determine OEV opportunities and the profitability of a liquidation.

For the implementation in this project, refer to the getDapiTransmutationCalls function for the transmutation component. Also, refer to simulateTransmutationMulticall for the actual transmutation simulation.

Run the OEV Bot Locally

  1. Setup Environment:

Copy .env.example to .env and populate it

cp .env.example .env
  1. Generate Wallet for the bot

A new mnemonic can be generated using the API3 Airnode CLI if required

pnpm dlx @api3/airnode-admin generate-mnemonic
  1. Fund the wallet with Blast ETH

The wallet will be capturing liquidations on the Blast network, so it needs to have some small ETH balance. The liquidations happen through a helper contract, which also requires some ETH deposit.

  1. Deploy and Fund the OrbitLiquidator Contract (First-time setup)
# Install the dependencies
pnpm i

# Build the project and contract
pnpm build

# Deploy the OrbitLiquidator contract
pnpm orbit-bot:cli-utils deploy
  1. Fund the OrbitLiquidator contract
pnpm orbit-bot:cli-utils deposit 0.01 # for 0.01 ETH
  1. Bridge funds to the OEV network

The wallet will be interacting with the OEV network for which it needs to have an ETH balance. You can use the official OEV bridge to bridge funds from the Ethereum network to the OEV network.

  1. Deposit funds to the OevAuctionHouse

You can use the OEV network explorer to call deposit with your wallet. Be sure to leave some ETH in the wallet as well to cover gas costs for the OEV network transactions.

  1. Run the Bot
pnpm orbit-bot

Additional commands

Withdraw all ETH from the OrbitLiquidator

pnpm orbit-bot:cli-utils withdraw-all-eth

Withdraw all tokens from the OrbitLiquidator

# The token address must be provided for the tokens to be withdrawn
pnpm orbit-bot:cli-utils withdraw-all-token [token-address]

Running the OEV Bot in Docker

Configuration

Ensure that the .env file has been populated as described in the "Run the OEV Bot Locally" section. This is necessary for running the app but not for building the Docker image.

Build Docker image

Build and run the OEV bot docker image locally using the following commands:

# Using the host machine's native CPU architecture
pnpm docker:build

# Run the bot
pnpm docker:run

About

An example bot demonstrating OEV extraction using API3 OEV network

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •