DEX & Algo Trading

Cross-Chain Arbitrage Detection: Ethereum vs Arbitrum vs Base

ClawDUX TeamApril 5, 20267 min read2 views

Cross-Chain Arbitrage Detection: Ethereum vs Arbitrum vs Base

Price differences across L1 and L2 chains create arbitrage opportunities — but bridge costs, latency, and gas differences make profitability calculation non-trivial.

Why Cross-Chain Spreads Exist

  1. Bridge latency: Moving assets between chains takes minutes to hours
  2. Fragmented liquidity: Same token, different pool depths per chain
  3. Gas cost asymmetry: Ethereum gas >> Arbitrum/Base gas
  4. Sequencer ordering: L2 sequencers process transactions differently

Multi-Chain Price Monitor

python
from web3 import Web3
from typing import Dict
import asyncio
import time

CHAIN_CONFIG = {
    'ethereum': {
        'rpc': 'https://ethereum-rpc.publicnode.com',
        'chain_id': 1,
        'gas_multiplier': 1.0,  # Base cost reference
    },
    'arbitrum': {
        'rpc': 'https://arbitrum-one-rpc.publicnode.com',
        'chain_id': 42161,
        'gas_multiplier': 0.01,  # ~100x cheaper
    },
    'base': {
        'rpc': 'https://base-rpc.publicnode.com',
        'chain_id': 8453,
        'gas_multiplier': 0.005,  # ~200x cheaper
    },
}

class CrossChainMonitor:
    def __init__(self):
        self.providers = {
            chain: Web3(Web3.HTTPProvider(config['rpc']))
            for chain, config in CHAIN_CONFIG.items()
        }
        self.latest_prices: Dict[str, Dict] = {}

    def get_price(self, chain: str, pool_address: str,
                  token0_decimals: int = 18,
                  token1_decimals: int = 6) -> float:
        """Get current price from a Uniswap V2-style pool."""
        w3 = self.providers[chain]
        pair_abi = [{
            "constant": True, "inputs": [],
            "name": "getReserves",
            "outputs": [
                {"name": "", "type": "uint112"},
                {"name": "", "type": "uint112"},
                {"name": "", "type": "uint32"}
            ],
            "type": "function"
        }]

        contract = w3.eth.contract(
            address=pool_address, abi=pair_abi
        )
        reserves = contract.functions.getReserves().call()

        r0 = reserves[0] / (10 ** token0_decimals)
        r1 = reserves[1] / (10 ** token1_decimals)
        return r1 / r0 if r0 > 0 else 0

    def detect_opportunities(
        self,
        pools: Dict[str, str],  # chain -> pool_address
        min_spread_bps: int = 50,
    ) -> list:
        """Detect cross-chain arbitrage opportunities."""
        prices = {}
        for chain, addr in pools.items():
            try:
                prices[chain] = self.get_price(chain, addr)
            except Exception as e:
                print(f"Error on {chain}: {e}")

        opportunities = []
        chains = list(prices.keys())

        for i in range(len(chains)):
            for j in range(i + 1, len(chains)):
                p_i = prices[chains[i]]
                p_j = prices[chains[j]]
                spread = abs(p_i - p_j) / min(p_i, p_j) * 10000

                if spread >= min_spread_bps:
                    buy_chain = chains[i] if p_i < p_j else chains[j]
                    sell_chain = chains[j] if p_i < p_j else chains[i]

                    opportunities.append({
                        'buy_chain': buy_chain,
                        'sell_chain': sell_chain,
                        'buy_price': min(p_i, p_j),
                        'sell_price': max(p_i, p_j),
                        'spread_bps': round(spread, 1),
                    })

        return opportunities

Cost Analysis

python
def calculate_arb_profit(
    spread_bps: float,
    trade_size_usd: float,
    buy_chain: str,
    sell_chain: str,
    bridge_fee_usd: float = 5.0,
    eth_price: float = 3500,
) -> dict:
    """Calculate net profit for a cross-chain arbitrage."""
    # Gross profit from spread
    gross = trade_size_usd * spread_bps / 10000

    # Gas costs per chain
    base_gas_cost = 300_000 * 30 * 1e-9 * eth_price  # ~$31
    buy_gas = base_gas_cost * CHAIN_CONFIG[buy_chain]['gas_multiplier']
    sell_gas = base_gas_cost * CHAIN_CONFIG[sell_chain]['gas_multiplier']

    # DEX fees (0.3% per swap)
    dex_fees = trade_size_usd * 0.003 * 2

    # Bridge cost
    total_cost = buy_gas + sell_gas + dex_fees + bridge_fee_usd

    return {
        'gross_profit': round(gross, 2),
        'gas_cost': round(buy_gas + sell_gas, 2),
        'dex_fees': round(dex_fees, 2),
        'bridge_fee': bridge_fee_usd,
        'total_cost': round(total_cost, 2),
        'net_profit': round(gross - total_cost, 2),
        'profitable': gross > total_cost,
        'min_trade_size': round(total_cost / (spread_bps / 10000), 2),
    }

Opportunity Frequency

Chain Pair Avg Spread Frequency Profitability
ETH ↔ Arbitrum 5-15 bps High Moderate (L1 gas)
ETH ↔ Base 10-30 bps Medium Higher (L2 gas)
Arbitrum ↔ Base 3-10 bps Low Low (small spreads)

ClawDUX operates on Ethereum mainnet for maximum security, but the cross-chain monitoring patterns shown here are valuable for strategies that trade across L2 ecosystems.

The core logic discussed in this article has been integrated into the ClawDUX API. Access ClawDUX-core for full permissions, or browse the marketplace to discover verified trading strategies.

#cross-chain#arbitrage#ethereum#arbitrum#base

Related Articles