Fake Pool Callback Drain
Exploit Transactions
0x1a6002d8aee205dff67cb2cdaf60569721655857d49ffe2ce81e10fde8c45946Victim Addresses
0x607742a2adea4037020e11bb67cb98e289e3ec7dBase0xddddf3d84a1e94036138cab7ff35d003c1207a77BaseLoss Breakdown
Similar Incidents
CivTrade Fake-Pool Callback Drain
44%USDC drain via unchecked Uniswap V3-style callback
41%MoltEVM Fake Spawner Drain
39%Unauthenticated Pancake Callback Drain
36%Unauthorized Vault Approval Drain
33%Balancer Callback Drain
33%Root Cause Analysis
Fake Pool Callback Drain
1. Incident Overview TL;DR
On Base block 28791090, EOA 0xcfad03a6f9dc4007eb3716fee51f108b00d6736d sent transaction 0x1a6002d8aee205dff67cb2cdaf60569721655857d49ffe2ce81e10fde8c45946 to its deployed helper 0x780e5Cb8DE79846f35541b700637057c9dddEd68. That helper impersonated a Uniswap V3 pool and called 0x607742a2adea4037020e11bb67cb98e289e3ec7d::uniswapV3SwapCallback twice, causing approved payer 0xddddf3d84a1e94036138cab7ff35d003c1207a77 to lose 22.51 WETH and 27,260 USDC.
The root cause is a callback-authentication failure. The victim helper trusted arbitrary msg.sender, queried token0() or token1() from that caller, and then executed transferFrom(payer, msg.sender, amount) without verifying that the caller was a canonical Uniswap V3 pool.
2. Key Background
Uniswap V3 swap callbacks are safe only when the callee authenticates the callback sender as the deterministic pool for the intended token pair and fee tier. If a callback implementation derives token identity from msg.sender before authenticating the caller, a fake pool can return arbitrary token addresses and redirect settlement to itself.
That is the relevant context here. The victim helper at 0x607742a2adea4037020e11bb67cb98e289e3ec7d had approval to spend both WETH and USDC from payer 0xddddf3d84a1e94036138cab7ff35d003c1207a77 before the exploit block. Pre-state observations at block 28791089 show at least 22517012217948887448 WETH, 27260506734 USDC, and ample allowances to the helper for both assets.
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK-category ACT exploit against an unauthenticated callback settlement helper. The vulnerable function is selector 0xfa461e33 on 0x607742a2adea4037020e11bb67cb98e289e3ec7d, corresponding to uniswapV3SwapCallback.
The bytecode shows two critical behaviors. First, the helper reads CALLER and issues a STATICCALL using selector 0x0dfe1681, which is token0(), and elsewhere the symmetric branch performs the equivalent caller-derived token lookup for the other side. Second, after resolving the token address, the helper builds selector 0x23b872dd and executes transferFrom(payer, CALLER, amount). The relevant disassembly fragments are:
0000017c: CALLER
...
0000019e: PUSH4 0x0dfe1681
...
000001c0: STATICCALL
...
0000020a: PUSH4 0x23b872dd
00000210: CALLER
and:
0000033f: PUSH4 0x23b872dd
00000345: CALLER
The broken invariant is: only the canonical Uniswap V3 pool for the expected swap path may trigger callback settlement, and settlement may only pull the owed token for that authenticated pool from the designated payer. The code-level breakpoint is the settlement branch inside uniswapV3SwapCallback where the helper queries token addresses from msg.sender and transfers funds to msg.sender before any factory validation.
4. Detailed Root Cause Analysis
The exploit pre-state is straightforward. At Base block 28791089, the victim helper was already deployed, the payer already held both target assets, and the payer had already approved the helper. That meant an attacker only needed a contract that implemented the expected callback surface and returned attacker-chosen token addresses.
The on-chain trace shows exactly that sequence. The fake pool 0x780e5Cb8DE79846f35541b700637057c9dddEd68 called the victim helper twice:
0x607742A2Adea4037020e11Bb67CB98E289E3eC7D::uniswapV3SwapCallback(
-125859570852398,
22510000000000000000,
0x...ddddf3d84a1e94036138cab7ff35d003c1207a77...
)
0x780e5Cb8DE79846f35541b700637057c9dddEd68::token1() -> 0x4200000000000000000000000000000000000006
WETH9::transferFrom(
0xddddF3D84a1E94036138Cab7ff35d003c1207A77,
0x780e5Cb8DE79846f35541b700637057c9dddEd68,
22510000000000000000
)
The second callback repeated the same pattern for USDC:
0x607742A2Adea4037020e11Bb67CB98E289E3eC7D::uniswapV3SwapCallback(
-125859570852398,
27260000000,
0x...ddddf3d84a1e94036138cab7ff35d003c1207a77...
)
0x780e5Cb8DE79846f35541b700637057c9dddEd68::token1() -> 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913
FiatTokenV2_2::transferFrom(
0xddddF3D84a1E94036138Cab7ff35d003c1207A77,
0x780e5Cb8DE79846f35541b700637057c9dddEd68,
27260000000
)
This is sufficient to establish the mechanism. The attacker controlled msg.sender, controlled the return value of token1(), and therefore controlled which token contract the victim helper used for settlement. Because the helper never authenticated the callback sender against a Uniswap V3 factory, the attacker could redirect any token for which the payer had granted allowance and still held balance.
The balance diff confirms the exact asset movement. The payer lost 22510000000000000000 WETH and 27260000000 USDC, while the fake pool gained the same amounts. The exploit therefore realized the stated ACT predicate directly through unauthorized allowance use rather than through price manipulation, privileged access, or hidden attacker-side artifacts.
5. Adversary Flow Analysis
The adversary cluster consists of EOA 0xcfad03a6f9dc4007eb3716fee51f108b00d6736d and its nonce-0 deployed fake pool 0x780e5Cb8DE79846f35541b700637057c9dddEd68. The EOA submitted the exploit transaction, and the fake pool was the direct recipient of the stolen assets.
The end-to-end flow was:
- The attacker deployed a fake pool contract that exposed the expected callback-facing surface and could return arbitrary token addresses.
- The fake pool called the victim helper's
uniswapV3SwapCallbackwith attacker-chosen deltas and calldata encoding the payer. - During the first callback, the fake pool returned WETH from
token1(), and the victim helper transferred22.51 WETHfrom the payer into the fake pool. - During the second callback, the fake pool returned USDC from
token1(), and the victim helper transferred27,260 USDCfrom the payer into the fake pool. - The attacker-controlled fake pool retained custody of both assets and the EOA only paid gas and L1 fee overhead.
Because all required ingredients were public and permissionless, any unprivileged adversary could reproduce the exploit by deploying an equivalent fake pool contract against a payer that had granted approval to the vulnerable helper.
6. Impact & Losses
The exploit drained two ERC20 assets from the approved payer in one transaction:
WETH: raw loss"22510000000000000000"withdecimal18USDC: raw loss"27260000000"withdecimal6
The payer address 0xddddf3d84a1e94036138cab7ff35d003c1207a77 was reduced to 7012217948887448 WETH and 506734 USDC in the traced transaction. The attacker EOA paid 386974209882 wei in fees, while the attacker-controlled contract received the stolen ERC20 balances.
7. References
- Seed transaction metadata:
0x1a6002d8aee205dff67cb2cdaf60569721655857d49ffe2ce81e10fde8c45946 - Seed trace showing the two callback-triggered
transferFromexecutions into the fake pool - Seed balance diff confirming payer losses and attacker-pool gains for WETH and USDC
- Victim helper disassembly for selector
0xfa461e33and theCALLER-derivedtransferFrombranches - Attacker helper disassembly showing the attacker-controlled callback surface and token-selection logic
- Pre-state observations at block
28791089confirming balances, allowances, and fake-pool deployment address derivation