Fix Uniswap V4 swap direction logic and Angstrom evt_index mismatch#9680
Open
bh2smith wants to merge 8 commits into
Open
Fix Uniswap V4 swap direction logic and Angstrom evt_index mismatch#9680bh2smith wants to merge 8 commits into
bh2smith wants to merge 8 commits into
Conversation
Use Swap event amounts instead of call output (output_swapDelta) for buy/sell direction. In V4, afterSwap hooks can modify the BalanceDelta after the Swap event is emitted but before the call returns, causing output_swapDelta to have different signs than the event amounts. This reverses token_bought/token_sold on pools with active afterSwap hooks. Also adds an `OR amount1 > 0` condition to handle edge cases where amount0 is zero (e.g. hooks absorbing the full counterparty amount).
The angstrom_bundle_orders macro generated synthetic evt_index values via ROW_NUMBER() instead of using the actual PoolManager Swap event log index. This caused dex.trades rows for Angstrom swaps to have evt_index values (1, 2, ...) that didn't match the real event indices, making it impossible to join with other systems that reference the actual evt_index. Fix: join bundle_orders with PoolManager_evt_Swap on tx_hash + pool_id (maker) to resolve the real evt_index, falling back to the synthetic value for orders without a corresponding Swap event.
After resolving real evt_index for bundle_orders, the composable and bundle paths can produce rows with the same (tx_hash, evt_index) for swaps that appear in both. Exclude composable rows that have a matching bundle order, since the bundle path has richer decoded data (taker, LP fees, protocol fees). Fixes CI: 362 unique key violations on angstrom_ethereum_base_trades.
The NOT EXISTS anti-join caused Trino to inline bundle_with_real_evt_index twice, doubling the nested bundle decoding pipeline and pushing the query to 801 stages (limit 500). Replace with a single-pass UNION ALL + ROW_NUMBER dedup that references each CTE only once, preferring bundle rows over composable rows on (tx_hash, evt_index) collision.
Use event amounts for direction (immune to afterSwap hook modifications) but call output amounts for values (includes hook adjustments, avoids zero-amount rows). Token addresses still use event-based direction. This resolves the regression where 5% of Ethereum rows had bought=0 or sold=0 due to using event amounts that reflect the core swap before hook adjustments zeroed out one side.
Enables partition pruning on PoolManager_evt_Swap during full builds. tx_hash functionally determines block, so output is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
jeff-dude
approved these changes
May 19, 2026
Member
|
i'll deploy when we have the env ready ✅ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two fixes for Uniswap V4 dex.trades accuracy:
1. Defensive fix to V4 swap direction logic (
uniswap_compatible_trades.sql)Use Swap event amounts (
e.amount0) instead of call output (c.amount0) for buy/sell direction, and addOR e.amount1 > INT256 '0'condition.In V4, afterSwap hooks can modify the BalanceDelta after the Swap event is emitted but before the call returns. Using event amounts is more reliable because they reflect the core swap before hook adjustments. The extra
ORcondition handles edge cases whereamount0 == 0(hooks absorbing the full counterparty amount).2. Fix Angstrom bundle orders evt_index (
angstrom_all_trades.sql)The
angstrom_bundle_ordersmacro generated syntheticevt_indexvalues viaROW_NUMBER()(1, 2, 3...) instead of the actual Swap event log index. This caused Angstrom swaps index.tradesto be unmatchable byevt_indexwith other systems that reference the real event index.Root cause investigation: A comparison query joining the dex trade stream with
dex.tradeson(block_number, tx_hash, evt_index)showed all Angstrom V4 swaps as "missing" — the synthetic evt_index never matched the real one.Verified with transactions:
0xbc49c090...: real evt_index=2, dex.trades had evt_index=10x5ab46bde...: real evt_index=3,4, dex.trades had evt_index=1,2Fix: Join bundle_orders with
PoolManager_evt_Swapon(tx_hash, pool_id)to resolve the realevt_index, falling back to the synthetic value for orders without a corresponding Swap event (e.g. off-chain matched user orders).Affected models
uniswap_compatible_v4_tradesmacro — used by all 15 chain-specific V4 base_trades modelsangstrom_all_tradesmacro — used byangstrom_ethereum_base_tradesTest plan
dex.tradesnow have correctevt_indexmatching Swap event logsCloses SIM-5858