Liquidation bot for Aave V3 on Arbitrum, Base, and Mantle. Flash loans for zero-capital execution. Two execution paths: Chainlink SVR sealed-bid auctions and direct transactions racing on price feed updates.
Solidity 0.8.20 Foundry TypeScript ethers v6 archived 2026-03
contracts/ Solidity (Foundry)
src/ FlashLoanLiquidator, F1SVRSolver, F1SVRSolverBase
test/ Unit + E2E fork tests
script/ Deployment scripts
bots/
arbitrum/ Arbitrum bot (Aave V3 + SVR)
base/ Base bot
mantle/ Mantle Aave V3 bot
dashboard/ Single-file HTML telemetry UI
docs/ This page
Listens to Chainlink's Smart Value Recapture gateway. Receives auction broadcasts for every liquidatable position, estimates profit, submits a bid. Winner is chosen by bid amount. Requires a bond posted to Atlas and a solver contract implementing atlasSolverCall.
Subscribes to Chainlink AnswerUpdated events. Pre-builds signed transactions for expected liquidation prices. On a matching event, broadcasts the cached TX over IPC to a colocated Arbitrum Nitro node.
The bot runs colocated with an Arbitrum Nitro full node. The node is the foundation for every latency number in this page:
AnswerUpdated events arrive via WebSocket subscription to the local node, not a paid RPC. Saves 20-50ms per oracle update./data/arbitrum/arbitrum.ipc): eth_sendRawTransaction takes ~1ms over IPC vs ~15ms over TCP to public RPC.getReserveData reads hit the node directly, no shared-provider throttling.wss://arb1.arbitrum.io/feed). The node doesn't serve that stream.Without a local node, detection still works, but execution latency adds ~15ms per TX and Chainlink WS subscriptions share provider quotas.
Three oracle sources feed a single in-memory price store. Each update triggers Health Factor recalc for every position exposed to the asset, in pure BigInt arithmetic, no RPC calls.
| Source | Transport | Latency vs chain | Confidence | Action |
|---|---|---|---|---|
| Coinbase / Kraken WebSocket | External WS | ~100ms ahead | 0.5 | Speculative fire |
| Arbitrum sequencer feed | External WS | ~250ms ahead | 0.95 | Speculative fire |
Chainlink AnswerUpdated | Local node WS | on-chain | 1.0 | Confirmed fire |
eth_call simulation | ~15ms | flash loan sim via local node IPC |
| gas calc | ~1ms | feeData cached 2s |
| nonce | ~0ms | warmed at startup, in-memory increment |
| sign + broadcast | ~17ms | eth_sendRawTransaction via IPC |
executeLiquidation(user, debtAsset, collateralAsset, amount, swapData)
└─ Aave.flashLoanSimple(debtAsset, amount)
└─ executeOperation callback:
1. Aave.liquidationCall(collateral, debt, user, amount, false)
2. swap: approvedRouter.call(swapData) | UniV3.exactInputSingle()
3. verify: debtBalance >= amountOwed
4. approve(Pool, amountOwed)
5. transfer(OWNER, profit)
Borrow event logs (~181K addresses), filters to active positions via Multicall3 (~12.8K positions in ~145s).TIER1_MIN_DEBT_USD get more frequent on-chain HF checks via multicall.cd contracts
forge install foundry-rs/forge-std
forge install FastLane-Labs/atlas
forge build
forge test # unit
forge test --match-contract F1SVRSolver_E2E_Test -v # fork E2E (~9 min)
cd bots/arbitrum
npm install
cp .env.example .env # fill PRIVATE_KEY, ARBITRUM_RPC_URL, contract addresses
npm run build
node dist/index.js # DRY_RUN=true by default
estimateGas to shave ~10ms. Edge-case liquidations needing more gas will revert.setAuthorizedCaller can invoke executeLiquidation. Loss of owner key = loss of contract.FlashLoanLiquidator.sol needs review before deploying with large collateral exposure.MIT. See LICENSE.