{"id":20093900,"url":"https://github.com/api3dao/oev-orbit-bot-example","last_synced_at":"2025-09-20T20:32:28.370Z","repository":{"id":247556096,"uuid":"816205253","full_name":"api3dao/oev-orbit-bot-example","owner":"api3dao","description":"An example bot demonstrating OEV extraction using API3 OEV network","archived":true,"fork":false,"pushed_at":"2024-07-09T10:02:30.000Z","size":455,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-02T16:16:13.805Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/api3dao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-17T08:56:19.000Z","updated_at":"2024-12-09T13:25:15.000Z","dependencies_parsed_at":"2024-07-09T11:14:59.246Z","dependency_job_id":null,"html_url":"https://github.com/api3dao/oev-orbit-bot-example","commit_stats":null,"previous_names":["api3dao/oev-orbit-bot-example"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/api3dao/oev-orbit-bot-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/api3dao%2Foev-orbit-bot-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/api3dao%2Foev-orbit-bot-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/api3dao%2Foev-orbit-bot-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/api3dao%2Foev-orbit-bot-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/api3dao","download_url":"https://codeload.github.com/api3dao/oev-orbit-bot-example/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/api3dao%2Foev-orbit-bot-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276153267,"owners_count":25594358,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-20T02:00:10.207Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T16:48:47.546Z","updated_at":"2025-09-20T20:32:28.053Z","avatar_url":"https://github.com/api3dao.png","language":"TypeScript","readme":"# OEV Orbit Bot Example\n\nThis repository contains an example OEV Searcher bot implementation targeting [Orbit Lending](https://orbitlending.io/).\nTo understand how OEV works, visit [the OEV documentation](https://docs.api3.org/reference/oev-network/).\n\nBefore running this application, be sure to read and understand the code.\n\n## Process Overview\n\nThe OEV bot follows this flow to extract OEV from Orbit Lending:\n\n1. **Initialisation**\n\n- Get log events from the Blast chain and build a list of accounts to watch for possible liquidation opportunities\n- Get log events from the OEV Network to determine awarded/live/lost bids\n\n2. **Main Loop**\n\n- Continuously watch log events from Orbit to maintain a list of accounts to watch\n- Attempt liquidations when opportunities are detected\n\n## Opportunity Detection and Value Extraction - In Depth\n\nGiven a list of accounts to watch, the app does the following: (Refer to `findOevLiquidation()`)\n\n### Search for an OEV Liquidation Opportunity\n\n- Simulate liquidation potential by [transmuting](#transmutation) the oracle's value for a feed\n  - Refer to the [Transmutation section of this README](#transmutation) for more information.\n  - Find Orbit's Price Oracle: `orbitSpaceStation.oracle()`\n    - Read the current value of the oracle for the target feed: `priceOracle.getUnderlyingPrice(oEtherV2)`\n  - Apply a transmutation value to the read price: `getPercentageValue(currentEthUsdPrice, 100.2)`\n  - Create a set of calls that can be used to transmute the value of the oracle temporarily\n    - Set the dAPI Name to a beacon we control:\n      `api3ServerV1Interface.encodeFunctionData('setDapiName', [dapiName, beaconId])`\n    - Set the value of the target beacon to our transmuted value: `updateBeaconWithSignedData`\n  - In a single call, apply the transmutation call data and retrieve account liquidity for all accounts\n    - refer to\n      [ExternalMulticallSimulator.sol](https://github.com/api3dao/oev-searcher/blob/main/contracts/api3-contracts/utils/ExternalMulticallSimulator.sol)\n- For all accounts assessed using a transmuted oracle value sort by the biggest shortfall.\n- For all shortfall accounts, re-simulate the transmutation call, simulate a liquidation and determine the profit.\n- Find the most profitable liquidation (using ETH and USD components).\n- At this point, the OEV bidding process begins. To understand the OEV bidding lifecycle refer to\n  [these OEV docs](https://docs.api3.org/reference/oev-network/overview/auction-cycle.html)\n\n  - [Bid on an update for the feed](https://docs.api3.org/reference/oev-network/searchers/submit-bids.html#with-an-expiration-timestamp)\n\n    ```typescript\n    const bidDetails: BidDetails = {\n      oevProxyAddress: contractAddresses.api3OevEthUsdProxy,\n      conditionType: BID_CONDITION.GTE,\n      conditionValue: transmutationValue,\n      updateSenderAddress: contractAddresses.multicall3,\n      nonce,\n    };\n    ```\n\n- Store the active bid's parameters\n\n### Attempt to Capture the OEV Liquidation Opportunity\n\nRefer to `attemptLiquidation()`. See the\n[OEV Network docs](https://docs.api3.org/reference/oev-network/searchers/submit-bids.html) for more information.\n\n- Listen for the award, expiry or loss of the active bid\n- If the bid is awarded, encode a multicall transaction containing\n  - Call #1: Call to the API3 Server with the awarded bid details as call data with value corresponding to the bid\n    amount\n  - Call #2: Call the Orbit Ether Liquidator contract with the liquidation parameters\n- Simulate the liquidation multicall and determine the profitability - bail if the profit is below the minimum\n- Execute the liquidation transaction\n- Report the fulfillment on the OEV Network\n\n### Transmutation\n\nIn order to bid on an OEV update an application will need to determine\n[the bid's parameters](https://docs.api3.org/reference/oev-network/searchers/submit-bids.html#arguments-for-placebidwithexpiration),\nand in particular:\n\n- The value of the bid (what will be paid for the bid in the Blast chain's native token)\n- The conditions under which the bid will be considered (less-than or greater-than a specific dAPI value)\n\nDetermining these values would generally require re-implementing the business logic of the dApp being targeted,\nsomething which is often very onerous. To make target dApp integration easier, API3 has built a contract that\nfacilitates the \"transmutation\" of a dAPI (from the concept of transmuting silver to gold).\n\n**Purpose of Transmutation:**\n\n- **Simulating Price Changes:** By transmuting the value of a data feed, we can simulate how changes in the price would\n  affect account liquidity. This helps in identifying liquidation opportunities without altering the actual market\n  conditions.\n- **Efficient Testing:** It allows for the efficient testing of various scenarios to find the most profitable\n  liquidation opportunities.\n- **Non-Intrusive:** This process is non-intrusive and does not affect the actual state of the blockchain since it's\n  done within a simulated environment.\n\nThe contract's relevant function is quoted below:\n\n```solidity\n/// @notice eth_call'ed while impersonating address-zero with zero gas\n/// price to simulate an external call\n/// @param target Target address of the external call\n/// @param data Calldata of the external call\n/// @return Returndata of the external call\n    function functionCall(\n        address target,\n        bytes memory data\n    ) external override returns (bytes memory) {\n        require(msg.sender == address(0), \"Sender address not zero\");\n        require(tx.gasprice == 0, \"Tx gas price not zero\");\n        return Address.functionCall(target, data);\n    }\n```\n\nSee the full `ExternalMulticallSimulator` contract implementation\n[here](https://github.com/api3dao/contracts/blob/7fb41c09953be41f1fab91affb2f75bc31368f65/contracts/utils/ExternalMulticallSimulator.sol).\n\nThis function can only be called with a signer address of zero, valid only for non-write operations like a simulated RPC\ncontract call. This can be executed via the [eth_call](https://www.quicknode.com/docs/ethereum/eth_call) RPC method. The\ndeployed contract instance has the\n[DAPI_NAME_SETTER_ROLE on the Api3ServerV1](https://github.com/api3dao/contracts/blob/d3c7dc6683445df14bf5f43b07e6ad9cc2813cc5/contracts/api3-server-v1/DapiServer.sol#L66),\nallowing it to change the datafeed a dAPI name points to in a non-writing and/or simulated transaction.\n\nWithin a simulated contract call, the app can:\n\n1. **Create and Sign a new Datafeed data point:**\n\n   - [Create and sign a new datafeed data point](https://github.com/api3dao/contracts/blob/d3c7dc6683445df14bf5f43b07e6ad9cc2813cc5/test/api3-server-v1/Api3ServerV1.sol.ts#L22)\n     (value and timestamp).\n\n2. **Simulate the Multicall Transaction:**\n   - Use the data feed update created earlier to initialize a datafeed our app controls, with a specified value (e.g.\n     the current target data feed's value + 1%).\n   - Set the target datafeed of the dApp's dAPI to the newly-initialized datafeed.\n   - Read the necessary functions on the target dApp to determine OEV opportunities and the profitability of a\n     liquidation.\n\nFor the implementation in this project, refer to the `getDapiTransmutationCalls` function for the transmutation\ncomponent. Also, refer to `simulateTransmutationMulticall` for the actual transmutation simulation.\n\n## Run the OEV Bot Locally\n\n1. **Setup Environment:**\n\nCopy `.env.example` to `.env` and populate it\n\n```sh\ncp .env.example .env\n```\n\n3. **Generate Wallet for the bot**\n\nA new mnemonic can be generated using the\n[API3 Airnode CLI](https://docs.api3.org/reference/airnode/latest/packages/admin-cli.html#generate-mnemonic) if required\n\n```sh\npnpm dlx @api3/airnode-admin generate-mnemonic\n```\n\n4. **Fund the wallet with Blast ETH**\n\nThe wallet will be capturing liquidations on the Blast network, so it needs to have some small ETH balance. The\nliquidations happen through a helper contract, which also requires some ETH deposit.\n\n5. **Deploy and Fund the OrbitLiquidator Contract (First-time setup)**\n\n```sh\n# Install the dependencies\npnpm i\n\n# Build the project and contract\npnpm build\n\n# Deploy the OrbitLiquidator contract\npnpm orbit-bot:cli-utils deploy\n```\n\n4. **Fund the OrbitLiquidator contract**\n\n```sh\npnpm orbit-bot:cli-utils deposit 0.01 # for 0.01 ETH\n```\n\n5. **Bridge funds to the OEV network**\n\nThe wallet will be interacting with the OEV network for which it needs to have an ETH balance. You can use the official\n[OEV bridge](https://docs.api3.org/reference/oev-network/overview/bridge-oev-network.html) to bridge funds from the\nEthereum network to the OEV network.\n\n1. **Deposit funds to the OevAuctionHouse**\n\nYou can use the\n[OEV network explorer](https://oev.explorer.api3.org/address/0x34f13A5C0AD750d212267bcBc230c87AEFD35CC5?tab=write_contract)\nto call `deposit` with your wallet. Be sure to leave some ETH in the wallet as well to cover gas costs for the OEV\nnetwork transactions.\n\n7. **Run the Bot**\n\n```sh\npnpm orbit-bot\n```\n\n### Additional commands\n\n#### Withdraw all ETH from the OrbitLiquidator\n\n```sh\npnpm orbit-bot:cli-utils withdraw-all-eth\n```\n\n#### Withdraw all tokens from the OrbitLiquidator\n\n```sh\n# The token address must be provided for the tokens to be withdrawn\npnpm orbit-bot:cli-utils withdraw-all-token [token-address]\n```\n\n## Running the OEV Bot in Docker\n\n### Configuration\n\nEnsure that the `.env` file has been populated as described in the \"Run the OEV Bot Locally\" section. This is necessary\nfor running the app but not for building the Docker image.\n\n### Build Docker image\n\nBuild and run the OEV bot docker image locally using the following commands:\n\n```bash\n# Using the host machine's native CPU architecture\npnpm docker:build\n\n# Run the bot\npnpm docker:run\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapi3dao%2Foev-orbit-bot-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapi3dao%2Foev-orbit-bot-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapi3dao%2Foev-orbit-bot-example/lists"}