Skip to content

feat(dex): add Origin ARM swaps to dex.trades#9891

Open
naddison36 wants to merge 10 commits into
duneanalytics:mainfrom
naddison36:codex/add-origin-arm-dex-trades
Open

feat(dex): add Origin ARM swaps to dex.trades#9891
naddison36 wants to merge 10 commits into
duneanalytics:mainfrom
naddison36:codex/add-origin-arm-dex-trades

Conversation

@naddison36

Copy link
Copy Markdown

Summary

Adds Origin ARM swaps on Ethereum to dex.trades.

The model includes swaps from:

  • Lido ARM
  • Ether.fi ARM
  • Ethena ARM

Both swapExactTokensForTokens and swapTokensForExactTokens are supported.

Methodology

The model uses decoded successful ARM calls to determine:

  • Tokens bought and sold
  • Raw input and output amounts
  • Taker
  • ARM contract
  • Transaction and block metadata

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 transfer or transferFrom call nested beneath the swap trace.

A deterministic evt_index is assigned using the call trace order, supporting transactions containing multiple ARM swaps.

Changes

  • Adds origin_arm_ethereum_base_trades
  • Registers the model in dex_ethereum_base_trades
  • Declares the six Origin Protocol decoded call sources
  • Adds Origin ARM to dex.info
  • Adds uniqueness and non-null tests
  • Adds regression seeds covering:
    • Legacy exact-input trace recovery
    • Legacy exact-output trace recovery
    • Ether.fi ARM
    • Ethena ARM

Validation

  • Successfully executed the rendered model against recent Dune data
  • Verified the expected 16-column DEX base-trades schema
  • Verified all four regression transactions and raw amounts against Dune
  • Validated YAML files
  • git diff --check passes

Project metadata

  • project: origin_arm
  • version: 1
  • blockchain: ethereum

@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
New trade-ingestion logic with custom trace parsing for missing amounts could mis-attribute volume if nested transfers are ambiguous; impact is limited to Origin ARM rows in dex metrics.

Overview
Adds Origin ARM Ethereum swaps into the shared DEX trades pipeline so they roll up to dex.trades alongside other venue base models.

Introduces origin_arm_ethereum_base_trades, which decodes successful swapExactTokensForTokens and swapTokensForExactTokens calls for Lido, Ether.fi, and Ethena ARM contracts (fixed addresses, from 2023-12-13). When older calls omit ABI output_amounts, the model backfills the missing leg from nested ERC-20 transfer / transferFrom traces under the swap call. evt_index is assigned deterministically from trace order for multi-swap txs.

Wiring and metadata: the model is ref’d in dex_ethereum_base_trades, origin_arm is added to dex.info, six origin_protocol_ethereum call sources are declared, and dbt tests plus a regression seed (four txs) validate uniqueness and raw amounts.

Reviewed by Cursor Bugbot for commit 64d0d50. Configure here.

@github-actions
github-actions Bot marked this pull request as draft July 16, 2026 06:39
@github-actions github-actions Bot added the WIP work in progress label Jul 16, 2026
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@github-actions github-actions Bot added the dbt: dex covers the DEX dbt subproject label Jul 16, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 64d0d50. Configure here.

@naddison36

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Jul 16, 2026
@naddison36
naddison36 marked this pull request as ready for review July 16, 2026 06:45
@github-actions github-actions Bot added ready-for-review this PR development is complete, please review and removed WIP work in progress labels Jul 16, 2026

@jeff-dude jeff-dude left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for raising. some feedback:

before merge

  1. Guard the recovery SUM() — 49% of swaps (33k of 68k) have NULL output_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 use MAX + COUNT(*) = 1 guard.
  2. 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?

@jeff-dude jeff-dude self-assigned this Jul 23, 2026
@jeff-dude jeff-dude added in review Assignee is currently reviewing the PR and removed ready-for-review this PR development is complete, please review labels Jul 23, 2026
@naddison36

Copy link
Copy Markdown
Author

Thanks for the detailed review.

I’ve addressed the feedback in separate commits:

  1. 36398d4 — replaced the recovery SUM() with MAX(...) HAVING COUNT(*) = 1. Recovery now fails closed when more than one qualifying transfer exists. I initially tested the direct-child approach, but Ether.fi’s transfer occurs beneath its implementation delegatecall, so that approach excluded valid swaps.

  2. 0b6ceb6 — added two distinct rows from a real multi-swap transaction, covering evt_index 1 and 2 and testing the ROW_NUMBER() ordering.

  3. 07a5a9e — added traces.block_date = swaps.block_date and traces.call_type = 'call' to improve partition pruning and exclude delegatecalls from recovery.

  4. I resubmitted the Ether.fi ARM proxy (0xfb0a3cf9b019bfd8827443d131b235b3e0fc58d2) to Dune for decoding. I also checked an affected transaction: both its proxy call and implementation delegatecall successfully return zero bytes, so output_amounts may correctly remain NULL after re-decoding. The guarded recovery path remains necessary.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dbt: dex covers the DEX dbt subproject in review Assignee is currently reviewing the PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants