Atomic cross-DEX arbitrage on Arbitrum

Off-chain services watch prices; a Solidity executor borrows through a flash loan, swaps across two DEXs and repays in one transaction, or reverts.

Role
Solo: contracts, off-chain services, operations
Period
Ongoing
Status
Runs on Arbitrum mainnet
Stack
  • Solidity
  • Node.js
  • Python
  • Balancer flash loans
  • Arbitrum
Flash-loan arbitrage: borrow, swap, repay, in one transaction Sequence diagram between Off-chain watcher, Executor contract, Balancer Vault, DEX A, DEX B. 1. Off-chain watcher to Off-chain watcher: quote pools, estimate gas 2. Off-chain watcher to Executor contract: execute(route, minProfit) 3. Executor contract to Balancer Vault: flashLoan(tokens, amounts) 4. Balancer Vault to Executor contract: receiveFlashLoan() 5. Executor contract to DEX A: swap A → B 6. Executor contract to DEX B: swap B → A 7. Executor contract to Executor contract: require(profit ≥ minProfit) 8. Executor contract to Balancer Vault: repay principal quote pools, estimate gas execute(route, minProfit) flashLoan(tokens, amounts) receiveFlashLoan() swap A → B swap B → A require(profit ≥ minProfit) repay principal One transaction: if any step fails, all of it reverts Off-chain watcher Executor contract Balancer Vault DEX A DEX B
Everything after execute() happens inside one transaction. If the profit check fails, the swaps and the loan unwind together.

The problem

Price differences between DEXs close within seconds, and holding capital to trade them ties up money and adds risk.

The system

  1. Off-chain Node.js and Python services watch pool prices and pending transactions, and estimate profit after gas.
  2. When an opportunity clears the threshold, they call a Solidity executor contract with the route and a minimum profit.
  3. The contract takes a Balancer flash loan, swaps across two DEXs and repays the loan inside the same transaction.
  4. If the trade would not clear the minimum at execution time, the whole transaction reverts and no position is left open.

Key decisions

Flash loans instead of held capital

WhyWorking capital is borrowed and returned within one transaction.

Trade-offOnly opportunities larger than gas costs are worth taking.

Enforce the profit check on-chain

WhyPrices move between simulation and inclusion; the contract enforces the minimum itself.

Trade-offMore gas on every attempt.

Arbitrum instead of Ethereum mainnet

WhyLower gas makes smaller spreads viable.

Trade-offFewer venues and thinner liquidity.

Results

  • Runs on Arbitrum mainnet
  • Contract and code walkthrough available on request

What I’d do next

Private order flow to cut failed attempts, and a public write-up of the risk controls.