All incidents

DOGGO/WETH cross-pool arbitrage MEV extracts WETH spread

Share
Sep 20, 2024 22:32 UTCMEVGain: 21.33 WETHManually checked1 exploit txWindow: Atomic

Root Cause Analysis

DOGGO/WETH cross-pool arbitrage MEV extracts WETH spread

1. Incident Overview TL;DR

An arbitrageur used a dedicated orchestrator contract to execute a single DOGGO/WETH cross-pool swap between a Uniswap V3 DOGGO/WETH pool and a Uniswap V2-style DOGGO/WETH pair on Ethereum mainnet block 20794803. In this transaction, the adversary drained approximately 21.33 WETH from the DOGGO/WETH V2 pool and realized a net profit of about 2.69 ETH after gas. All involved contracts (DOGGO token, DOGGO/WETH pools, WETH9, Uniswap V2 router) behaved according to their intended semantics; the profit stems from a transient price misalignment between pools rather than any smart contract bug.

The root cause is a MEV-style ACT opportunity: unprivileged adversaries can exploit DOGGO/WETH price differences between standard Uniswap V2/V3 pools, in the presence of DOGGO’s fee-on-transfer behavior, without violating any protocol-level safety invariant or exploiting faulty access control.

2. Key Background

DOGGO is a fee-on-transfer ERC20 token deployed on Ethereum at:

// DOGGO token
address constant DOGGO = 0x240cd7b53d364a208ed41f8ced4965d11f571b7a;

Heimdall decompilation of the DOGGO contract shows a fixed total supply, standard ERC20 interfaces, and transfer logic that applies a configurable tax percentage on each transfer. The taxed portion is credited to the token contract’s own balance, with the remainder delivered to the recipient. There are max-transaction and max-wallet size checks, anti-bot style per-address flags, and launch-time constraints, but no hidden mint, burn, or rebasing mechanisms.

DOGGO/WETH liquidity is provided in at least two public pools:

// DOGGO/WETH pools
address constant DOGGO_WETH_V2_PAIR = 0x7eb6d3466600b4857eb60a19e0d2115e65aa815e; // Uniswap V2-style
address constant DOGGO_WETH_V3_POOL = 0xea5a12a857e8302d70fcb1123d5f8f57ef7b7d0b; // Uniswap V3 pool
address constant WETH9              = 0xC02aaa39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant UNISWAP_V2_ROUTER  = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;

The DOGGO/WETH V2 pair at 0x7eb6... is a canonical Uniswap V2-style AMM, as confirmed by the decompiled code in the Heimdall artifacts. It exposes the standard mint, burn, swap, skim, and sync functions, enforces a constant-product invariant with a 0.3% fee via 997/1000 factors, and uses a reentrancy lock flag in the same way as the reference UniswapV2Pair implementation. The only notable deviation is a non-standard flash swap callback selector, which does not alter reserve accounting or invariants.

An arbitrage orchestrator contract at:

// Arbitrage orchestrator
address constant ORCHESTRATOR = 0xbdb0bc0941ba81672593cd8b3f9281789f2754d1;

is used to execute the DOGGO/WETH trade path. Heimdall decompilation and disassembly show that this contract:

  • Routes through Uniswap V2 and Balancer using hard-coded addresses (including WETH9, the Uniswap V2 router, and the Balancer Vault).
  • Uses tx.origin checks tied to:
address constant ADVERSARY_EOA = 0x7248939f65bdd23aab9eaab1bc4a4f909567486e;

to gate its main arbitrage entrypoints.

  • Invokes WETH.withdraw(uint256) to unwrap WETH into ETH before distributing profits.

The incident transaction under analysis is:

{
  "chainid": 1,
  "txhash": "0x9e074d70e4f9022cba33c1417a6f6338d8248b67d6141c9a32913ca567d0efca",
  "block_number": "20794803"
}

This transaction is sent by ADVERSARY_EOA and targets ORCHESTRATOR, with calldata selector 0x3d35e910. The pre-state sigma_B is reconstructed from tx_state_diff_prestateTracer.json and balance_diff.json, which provide account balances, storage slots, and token reserve values immediately before the transaction executes.

3. Vulnerability Analysis & Root Cause Summary

The analyzed event is not a smart contract vulnerability in the traditional sense, but a MEV-style arbitrage. The DOGGO token contract, DOGGO/WETH V2 pair, Uniswap V3 pool, and WETH9 all enforce their documented invariants and access controls throughout the transaction. There is no malfunctioning logic, missing access control, or broken arithmetic.

Instead, the exploitable condition is an open-market price discrepancy between the DOGGO/WETH V3 pool and the DOGGO/WETH V2 pair in the pre-state sigma_B. DOGGO’s fee-on-transfer behavior contributes to path-dependent pricing and can amplify divergence between pools, but the essential phenomenon is a standard cross-pool arbitrage opportunity: DOGGO is relatively cheaper in one pool and more expensive in the other.

The root cause is therefore:

  • Existence of multiple public DOGGO/WETH liquidity pools (Uniswap V2 and V3) with independent pricing.
  • Fee-on-transfer mechanics in DOGGO causing slightly different effective trade prices along different routes.
  • Absence of any protocol-level invariant enforcing price equality across pools, which is expected in permissionless AMM ecosystems.

Unprivileged adversaries can realize profit by executing the cross-pool swap path from the cheaper to the more expensive pool whenever these conditions arise.

4. Detailed Root Cause Analysis

This section follows the concrete transaction 0x9e07... using on-chain traces and state diffs.

4.1 Pre-state sigma_B and price discrepancy

From tx_state_diff_prestateTracer.json and balance_diff.json, we obtain:

{
  "erc20_balance_deltas": [
    {
      "token": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
      "holder": "0x7eb6d3466600b4857eb60a19e0d2115e65aa815e",
      "before": "73702152156870919837",
      "after": "52376636860320832574",
      "delta": "-21325515296550087263",
      "contract_name": "WETH9"
    }
  ]
}

This shows that before the transaction, the DOGGO/WETH V2 pair holds 73.702152156870919837 WETH and ends with 52.376636860320832574 WETH, losing 21.325515296550087263 WETH to the arbitrage. The prestate data for the DOGGO/WETH V3 pool and DOGGO token balances (via tx_state_diff_prestateTracer.json) confirm that both pools have sufficient reserves to support a cross-pool DOGGO-for-WETH trade.

Given the DOGGO reserve values observed in the V3 pool and V2 pair, standard Uniswap pricing formulas imply a DOGGO/WETH price mismatch that makes the following path profitable:

  1. Acquire DOGGO from the V3 pool.
  2. Sell DOGGO into the V2 pair for WETH.
  3. Unwrap WETH to ETH and distribute ETH to the arbitrageur.

4.2 Orchestrator entry and DOGGO acquisition from Uniswap V3

The call trace (tx_trace_callTracer.json) begins with ADVERSARY_EOA calling ORCHESTRATOR:

{
  "from": "0x7248939f65bdd23aab9eaab1bc4a4f909567486e",
  "to": "0xbdb0bc0941ba81672593cd8b3f9281789f2754d1",
  "input": "0x3d35e910...",
  "type": "CALL"
}

Inside ORCHESTRATOR, the contract calls the DOGGO/WETH V3 pool at 0xea5... to pull DOGGO out:

{
  "from": "0xbdb0bc0941ba81672593cd8b3f9281789f2754d1",
  "to": "0xea5a12a857e8302d70fcb1123d5f8f57ef7b7d0b",
  "type": "CALL",
  "input": "0x490e6cbc..."
}

Within the V3 pool, the trace shows DOGGO being transferred to ORCHESTRATOR:

{
  "from": "0xea5a12a857e8302d70fcb1123d5f8f57ef7b7d0b",
  "to": "0x240cd7b53d364a208ed41f8ced4965d11f571b7a",
  "type": "CALL",
  "input": "0xa9059cbb...000000000000000000000000bdb0bc09...00000000000000000000000000000000000000000000000068aef806f3a5e28a"
}

This corresponds to DOGGO.transfer(ORCHESTRATOR, 0x68aef806f3a5e28a) from the V3 pool, giving ORCHESTRATOR a large balance of DOGGO.

4.3 DOGGO approval and sale into DOGGO/WETH V2 pair via Uniswap V2 router

After receiving DOGGO, ORCHESTRATOR prepares to sell it into the DOGGO/WETH V2 pair by approving the Uniswap V2 router:

{
  "from": "0xbdb0bc0941ba81672593cd8b3f9281789f2754d1",
  "to": "0x240cd7b53d364a208ed41f8ced4965d11f571b7a",
  "type": "CALL",
  "input": "0x095ea7b3...0000000000000000000000007a250d56...0000000000000000000000000000000000000000000000001b88ac214f42a9f0"
}

This is DOGGO.approve(UNISWAP_V2_ROUTER, 0x1b88ac214f42a9f0). The router then pulls DOGGO from ORCHESTRATOR and sends it into the DOGGO/WETH V2 pair:

{
  "from": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",
  "to": "0x240cd7b53d364a208ed41f8ced4965d11f571b7a",
  "type": "CALL",
  "input": "0x23b872dd...000000000000000000000000bdb0bc09...0000000000000000000000007eb6d34666...0000000000000000000000000000000000000000000000001b88ac214f42a9f0"
}

This is DOGGO.transferFrom(ORCHESTRATOR, DOGGO_WETH_V2_PAIR, 0x1b88ac214f42a9f0) through the router. Once DOGGO enters the V2 pair, the pair’s swap function sends WETH out to ORCHESTRATOR according to the constant-product pricing formula and in consideration of DOGGO’s fee-on-transfer behavior (the DOGGO contract keeps part of the sent amount as tax, which the V2 pair’s accounting treats as part of the input amount).

The net effect, confirmed by the ERC20 balance delta snippet above, is that the V2 pair’s WETH balance decreases by 21.325515296550087263 WETH.

4.4 WETH unwrapping and ETH distribution

After receiving WETH from the V2 pair, ORCHESTRATOR converts WETH to ETH by calling WETH.withdraw:

{
  "from": "0xbdb0bc0941ba81672593cd8b3f9281789f2754d1",
  "to": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
  "type": "CALL",
  "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000027326e81934c7803"
}

This is WETH.withdraw(0x27326e81934c7803), followed by an internal transfer from WETH9 back to ORCHESTRATOR carrying that ETH value. The orchestrator then forwards ETH to two EOAs:

{
  "from": "0xbdb0bc0941ba81672593cd8b3f9281789f2754d1",
  "to": "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5",
  "type": "CALL",
  "value": "0x179fa97e3874722"
},
{
  "from": "0xbdb0bc0941ba81672593cd8b3f9281789f2754d1",
  "to": "0x7248939f65bdd23aab9eaab1bc4a4f909567486e",
  "type": "CALL",
  "value": "0x25b873e9afc5325b"
}

These correspond to ETH transfers to:

  • 0x9522... — the fee-recipient/MEV relay wallet.
  • ADVERSARY_EOA — the primary arbitrageur.

4.5 Profit computation and invariants

balance_diff.json shows the net ETH balance changes:

{
  "native_balance_deltas": [
    {
      "address": "0x7248939f65bdd23aab9eaab1bc4a4f909567486e",
      "before_wei": "10956091071863561681",
      "after_wei": "13661104457503070866",
      "delta_wei": "2705013385639509185"
    },
    {
      "address": "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5",
      "delta_wei": "106391596484216610"
    },
    {
      "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
      "delta_wei": "-21325515296550087263"
    }
  ]
}

From the transaction receipt (gasUsed and effectiveGasPrice), the gas fee paid by ADVERSARY_EOA is 13036436992095264 wei. The root cause analysis computes the net profit for ADVERSARY_EOA as:

value_delta_in_reference_asset = 2705013385639509185 - 13036436992095264
                               = 2691976948647413921 wei > 0

This confirms that the arbitrage is profitable in ETH terms after accounting for gas, independent of the ETH sent to 0x9522....

Throughout this sequence:

  • DOGGO’s transfer and fee accounting behave as specified in the decompiled token contract.
  • The DOGGO/WETH V2 pair’s mint/burn/swap logic preserves the constant-product invariant modulo trading fee; no invariant check reverts.
  • The DOGGO/WETH V3 pool behaves as a standard Uniswap V3 pool, correctly transferring DOGGO out and updating its internal state.
  • WETH9 correctly wraps and unwraps ETH.

There is no evidence of storage corruption, reentrancy, access-control bypass, or arithmetic error. The opportunity exists purely because the two public AMM pools do not maintain synchronized prices.

4.6 Invariant and breakpoint

For this MEV-style arbitrage, the relevant invariants and breakpoint are:

  • Protocol invariants:
    • Uniswap V2/V3 pools maintain their respective constant-product-style invariants (adjusted for fees).
    • DOGGO maintains fixed total supply and fee-on-transfer accounting.
  • Cross-pool price equality:
    • There is no protocol-level invariant requiring DOGGO/WETH prices to be equal across different pools.

In the incident transaction, the first set of invariants holds throughout; no invariant violation or access-control failure occurs. The break exploited by the adversary is not a violated invariant but an allowed configuration of the global state sigma_B: DOGGO/WETH prices differ between the V3 pool and the V2 pair enough to make the cross-pool route profitable.

5. Adversary Flow Analysis

The adversary-related cluster comprises:

address constant ADVERSARY_EOA        = 0x7248939f65bdd23aab9eaab1bc4a4f909567486e;
address constant ORCHESTRATOR         = 0xbdb0bc0941ba81672593cd8b3f9281789f2754d1;
address constant FEE_RECIPIENT_EOA    = 0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5;

ORCHESTRATOR is controlled by ADVERSARY_EOA via tx.origin checks, and the transaction sequence is entirely contained in a single transaction 0x9e07...:

  1. ADVERSARY_EOA calls ORCHESTRATOR with selector 0x3d35e910 and parameters specifying DOGGO, DOGGO/WETH pools, and trade amounts.
  2. ORCHESTRATOR verifies that tx.origin == ADVERSARY_EOA using hard-coded address comparisons, enforcing cluster control.
  3. ORCHESTRATOR calls the DOGGO/WETH V3 pool to pull DOGGO out, receiving a large amount of DOGGO at the V3-implied price.
  4. ORCHESTRATOR approves the Uniswap V2 router to spend DOGGO.
  5. The router executes a swap path that transfers DOGGO from ORCHESTRATOR to the DOGGO/WETH V2 pair and receives WETH in return at the V2-implied price.
  6. ORCHESTRATOR calls WETH9 to unwrap the received WETH into ETH.
  7. ORCHESTRATOR sends a small portion of ETH to FEE_RECIPIENT_EOA and the remaining ETH to ADVERSARY_EOA.

This flow is fully reconstructable from tx_trace_callTracer.json. The only transaction in the adversary lifecycle for this incident is the single arbitrage transaction; there are no auxiliary setup or cleanup transactions required to realize the profit.

Importantly, while ORCHESTRATOR uses tx.origin to restrict who can use this particular arbitrage contract, the strategy itself is ACT: any unprivileged adversary cluster could deploy an equivalent orchestrator (with its own origin checks and parameters) that performs the same sequence of calls against the public DOGGO/WETH pools from the same pre-state sigma_B.

6. Impact & Losses

The immediate on-chain impact is on the DOGGO/WETH V2 liquidity providers. From balance_diff.json:

  • The DOGGO/WETH V2 pair at 0x7eb6... loses 21.325515296550087263 WETH (delta = -21325515296550087263 in 18-decimal units).
  • ADVERSARY_EOA’s ETH balance increases by 2.705013385639509185 ETH before gas, and 2.691976948647413921 ETH net after gas.
  • FEE_RECIPIENT_EOA receives an additional 0.106391596484216610 ETH.

DOGGO token balances and pool accounting remain internally consistent; trading can continue in both the V2 pair and V3 pool after the transaction. No user funds are frozen, no protocol is halted, and there is no governance impact.

This incident is best characterized as MEV extraction:

  • Victim: DOGGO/WETH V2 liquidity providers, whose pool is traded against at an unfavorable price relative to the V3 pool.
  • Loss: approximately 21.33 WETH in value is transferred from the pool to the adversary cluster in a single block, in line with expected MEV activity in open AMM markets.

7. References

  • Seed transaction and balance diffs:
    • artifacts/root_cause/seed/1/0x9e074d70e4f9022cba33c1417a6f6338d8248b67d6141c9a32913ca567d0efca/balance_diff.json
    • artifacts/root_cause/data_collector/iter_1/tx/1/0x9e074d70e4f9022cba33c1417a6f6338d8248b67d6141c9a32913ca567d0efca/tx_state_diff_prestateTracer.json
  • Full transaction traces:
    • artifacts/root_cause/data_collector/iter_1/tx/1/0x9e074d70e4f9022cba33c1417a6f6338d8248b67d6141c9a32913ca567d0efca/tx_trace_callTracer.json
    • artifacts/root_cause/data_collector/iter_1/tx/1/0x9e074d70e4f9022cba33c1417a6f6338d8248b67d6141c9a32913ca567d0efca/tx_metadata.json
    • artifacts/root_cause/data_collector/iter_1/tx/1/0x9e074d70e4f9022cba33c1417a6f6338d8248b67d6141c9a32913ca567d0efca/tx_receipt.json
  • Decompilation summaries for key contracts:
    • DOGGO token 0x240c...: artifacts/root_cause/data_collector/iter_2/contract/1/0x240cd7b53d364a208ed41f8ced4965d11f571b7a/analysis_doggo_token_summary.md
    • DOGGO/WETH V2 pair 0x7eb6...: artifacts/root_cause/data_collector/iter_2/contract/1/0x7eb6d3466600b4857eb60a19e0d2115e65aa815e/analysis_doggo_weth_pool_summary.md
    • Orchestrator 0xbdb0...: artifacts/root_cause/data_collector/iter_2/contract/1/0xbdb0bc0941ba81672593cd8b3f9281789f2754d1/analysis_orchestrator_summary.md
  • Address activity:
    • FEE_RECIPIENT_EOA 0x9522... tx history: artifacts/root_cause/data_collector/iter_2/address/1/0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5/txlist.json