feat(dex): add Origin ARM swaps to dex.trades#9891
Conversation
PR SummaryMedium Risk Overview Introduces Wiring and metadata: the model is Reviewed by Cursor Bugbot for commit 64d0d50. Configure here. |
|
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 64d0d50. Configure here.
| {% if is_incremental() -%} | ||
| AND {{ incremental_predicate('traces.block_time') }} | ||
| {% endif -%} | ||
| GROUP BY 1, 2, 3, 4 |
There was a problem hiding this comment.
Recovery sums all matching transfers
Medium Severity
Legacy amount recovery in missing_amounts uses SUM over every successful nested trace that shares the swap trace prefix and matches the ARM from, token contract to, and ERC-20 selector. When more than one such transfer exists under one swap (splits, refunds, or multi-step internals), the recovered buy or sell raw amount is the total of those calls, not a single swap leg, which can inflate token_bought_amount_raw or token_sold_amount_raw in dex.trades.
Reviewed by Cursor Bugbot for commit 64d0d50. Configure here.
|
I have read the CLA Document and I hereby sign the CLA |
jeff-dude
left a comment
There was a problem hiding this comment.
thank you for raising. some feedback:
before merge
- Guard the recovery
SUM()— 49% of swaps (33k of 68k) have NULLoutput_amounts, ongoing today, so this is your hot path. A second qualifying transfer under a swap trace (fee, refund, sweep) silently inflates amounts. Restrict to direct children (CARDINALITY(traces.trace_address) = CARDINALITY(swaps.trace_address) + 1) or useMAX+COUNT(*) = 1guard. - Add a multi-swap seed row — all 4 rows are
evt_index = 1; the ROW_NUMBER logic is untested.
Strongly encouraged:
3. Add AND traces.block_date = swaps.block_date and AND traces.call_type = 'call' to the traces join ON — enables partition pruning (full refresh currently scans ~1.7 TB) and blocks delegatecall double-counting.
4. Ether.fi NULLs start exactly 2025-10-31 — looks like an implementation ABI missing from decoding. Re-submitting it would shrink your recovery path.
Questions:
- Does the ARM guarantee exactly one transfer per leg per swap?
|
Thanks for the detailed review. I’ve addressed the feedback in separate commits:
Regarding the transfer guarantee: current ARM implementations perform one input transfer and one output transfer per swap, but this is not an immutable guarantee across upgrades. The MAX + COUNT(*) = 1 guard ensures recovery only accepts exactly one qualifying transfer and excludes ambiguous swaps. |


Summary
Adds Origin ARM swaps on Ethereum to
dex.trades.The model includes swaps from:
Both
swapExactTokensForTokensandswapTokensForExactTokensare supported.Methodology
The model uses decoded successful ARM calls to determine:
Some older ARM implementations do not return an ABI-encoded amounts array. For these calls, the missing amount is recovered from the corresponding ERC-20
transferortransferFromcall nested beneath the swap trace.A deterministic
evt_indexis assigned using the call trace order, supporting transactions containing multiple ARM swaps.Changes
origin_arm_ethereum_base_tradesdex_ethereum_base_tradesdex.infoValidation
git diff --checkpassesProject metadata
project:origin_armversion:1blockchain:ethereum