feat: add Stratabook volume/fees adapter (Solana CLOB) - #8722
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Summary by CodeRabbit
WalkthroughAdds a Dune-based Solana Stratabook adapter. It identifies successful CLOB fills, matches them to token transfers, aggregates base-token volume and taker fees by mint, and exports hourly fee and revenue metrics. ChangesStratabook Solana Dune integration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant StratabookAdapter
participant Dune
participant SolanaCLOB
StratabookAdapter->>Dune: Submit the requested time-range query
Dune->>SolanaCLOB: Read successful OrderFilled events and token transfers
SolanaCLOB-->>Dune: Return fill, transfer, market, and mint data
Dune-->>StratabookAdapter: Return grouped volume and fee rows
StratabookAdapter->>StratabookAdapter: Create volume and revenue balances
Suggested labels: 🚥 Pre-merge checks | ✅ 12 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (12 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The stratabook adapter exports: |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dexs/stratabook/index.ts`:
- Around line 30-33: Correct the verification-date claim in the module
documentation near the market PDA account-layout description: replace the future
date with the actual completed verification date, or explicitly state that
verification is planned if it has not yet occurred.
- Around line 241-244: Update the log-processing loop around EVENT_ORDER_FILLED
to track Solana program invocation context, activating decoding only after a log
entry invokes CLOB_PROGRAM and suspending it when that invocation ends. Require
the context to be active before decoding any “Program data:” payload, while
preserving the existing length and event-tag checks.
- Around line 202-203: Prevent incomplete collection from producing balances in
the Stratabook adapter: at dexs/stratabook/index.ts lines 202-203, do not return
balances when the scan reaches MAX_SIGS_PER_RUN before exhausting the historical
window; at lines 176-178, rethrow persistent transaction-retrieval failures
instead of appending null or omitting transactions; at lines 192-193, treat an
empty market result as unavailable or invalid unless the adapter can prove no
markets existed.
- Around line 268-275: Update the SimpleAdapter configuration in the adapter
declaration to use the version 2 root shape: set pullHourly: true explicitly and
move chains, start, and fetch to the root level, using a shared chains array
containing CHAIN.SOLANA. Preserve the existing start date and fetch
implementation.
- Around line 220-223: Update the transaction filter in the loop over txs to
skip any transaction whose tx.meta.err is set, before accessing accounts or
parsing logs. Preserve the existing metadata, blockTime, and time-range checks
for transactions without errors.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 89b0f106-1404-445e-8f5f-43ce2fc6bdb9
📒 Files selected for processing (1)
dexs/stratabook/index.ts
…CLOB invocation context, completeness guards
|
Addressed all 5 CodeRabbit comments:
Validated: adapter test passes, ts-check passes, and a direct fetch over Aug 9-10 decodes the real 8 fills (fees = 10bps taker on volume). |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
dexs/stratabook/index.ts (1)
186-190: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winReport retained fees as
dailyProtocolRevenue.The adapter adds every taker fee to
dailyRevenue. It reports zerodailySupplySideRevenue. Therefore, the same amount is protocol revenue.Create, populate, and return
dailyProtocolRevenue. Add the matchingProtocolRevenuemethodology entry.Proposed fix
const dailyFees = createBalances(); const dailyRevenue = createBalances(); + const dailyProtocolRevenue = createBalances(); const dailySupplySideRevenue = createBalances(); dailyFees.add(market.baseMint, takerFee.toString()); dailyRevenue.add(market.baseMint, takerFee.toString()); + dailyProtocolRevenue.add(market.baseMint, takerFee.toString()); - return { dailyVolume, dailyFees, dailyRevenue, dailySupplySideRevenue }; + return { dailyVolume, dailyFees, dailyRevenue, dailyProtocolRevenue, dailySupplySideRevenue };As per coding guidelines, “Flag missing supply-side deductions, missing protocol/holder splits.”
Also applies to: 261-262, 279-279
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dexs/stratabook/index.ts` around lines 186 - 190, Update the adapter’s daily fee accounting to introduce and populate dailyProtocolRevenue alongside dailyRevenue, assigning retained taker fees to protocol revenue while leaving dailySupplySideRevenue at zero. Return dailyProtocolRevenue from the adapter and add the corresponding ProtocolRevenue methodology entry, including the related logic at the other indicated fee-processing locations.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dexs/stratabook/index.ts`:
- Around line 241-248: Replace the boolean inClobInvoke tracking around the
transaction log loop with an invocation stack that pushes every Program <id>
invoke record and pops the matching completion record. Decode Program data
payloads only when CLOB_PROGRAM is the current stack top, preventing nested
program events from being counted while preserving CLOB event handling.
---
Outside diff comments:
In `@dexs/stratabook/index.ts`:
- Around line 186-190: Update the adapter’s daily fee accounting to introduce
and populate dailyProtocolRevenue alongside dailyRevenue, assigning retained
taker fees to protocol revenue while leaving dailySupplySideRevenue at zero.
Return dailyProtocolRevenue from the adapter and add the corresponding
ProtocolRevenue methodology entry, including the related logic at the other
indicated fee-processing locations.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 617dad38-de07-4dea-b3b8-7328c083c23d
📒 Files selected for processing (1)
dexs/stratabook/index.ts
|
The stratabook adapter exports: ====== TOTAL DAILY AGGREGATED (sum of slots per chain) ====== |
|
Addressed both new comments:
Validated: ts-check passes, adapter test passes, direct fetch over Aug 9-10 decodes the real fills with fees = 10bps taker and protocolRevenue = revenue. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dexs/stratabook/index.ts`:
- Around line 273-275: Update the fee writes in the daily fee processing flow so
dailyFees uses the “Swap Fees” label, while dailyRevenue and
dailyProtocolRevenue use “Swap Fees To Protocol”; declare both labels under
their corresponding breakdownMethodology keys and preserve the existing
market.baseMint and takerFee values.
- Around line 269-275: Update the three Balances.add calls for takerFee in the
fee-accounting block to pass "swap fees" as their third argument: dailyFees,
dailyRevenue, and dailyProtocolRevenue. Preserve the existing mint and fee
amount arguments.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 57db4ada-5f5b-43b5-ab7d-c219c7cceb45
📒 Files selected for processing (1)
dexs/stratabook/index.ts
|
The stratabook adapter exports: ====== TOTAL DAILY AGGREGATED (sum of slots per chain) ====== |
|
Addressed both comments — the fee calls now pass breakdown labels: and declares the matching labels (Swap Fees / Swap Fees To Protocol) under Fees, Revenue, and ProtocolRevenue. ts-check passes locally; direct fetch over the live window still decodes fills correctly. |
|
Addressed both comments — the fee
and |
|
The stratabook adapter exports: ====== TOTAL DAILY AGGREGATED (sum of slots per chain) ====== |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai approve |
✅ Action performedComments resolved and changes approved. |
|
@limeneris-beep thanks for the PR |
…ad of Solana RPC (per maintainer request)
|
Done — adapter now sources volume + fees entirely from Dune Analytics, zero Solana RPC calls. Thanks for the review @bheluga! What changedData source: Volume: each Fees: taker fee = fill_size × Market.taker_fee_bps, computed in SQL. One honest caveat on feesI verified the fee rate is not uniform: the 9 live markets carry
ts-check + adapter test pass; CI re-running now. |
✅ Action performedReview finished.
|
|
The stratabook adapter exports: |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
dexs/stratabook/index.ts (1)
103-116: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftRestrict event decoding to the active CLOB invocation.
fillsaccepts every matching payload ins.log_messages. A CLOB instruction can execute nested programs. A nested program can emit a tag-3 payload that this query parses as anOrderFilledevent. The query then attributes that payload to CLOB accounts and transfers. This can inflate volume, fees, and revenue.Parse the ordered invocation logs and decode payloads only when
CLOB_PROGRAMis the invocation-stack top. Use an emitter-specific Dune field if one exists. This reintroduces the previously resolved invocation-context issue after the Dune migration. Dune documents thatlog_messagescontains logs emitted during an instruction’s execution. (dune.mintlify.app)As per path instructions, review DEX adapters for “Volume calculation accuracy.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dexs/stratabook/index.ts` around lines 103 - 116, Update the fills CTE in the Stratabook query to decode tag-3 payloads only when the ordered invocation logs identify CLOB_PROGRAM as the active invocation-stack top, using Dune’s emitter-specific field if available. Do not treat every matching entry in s.log_messages as a CLOB event; preserve attribution only for payloads emitted by the active CLOB invocation.Sources: Path instructions, MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@dexs/stratabook/index.ts`:
- Around line 103-116: Update the fills CTE in the Stratabook query to decode
tag-3 payloads only when the ordered invocation logs identify CLOB_PROGRAM as
the active invocation-stack top, using Dune’s emitter-specific field if
available. Do not treat every matching entry in s.log_messages as a CLOB event;
preserve attribution only for payloads emitted by the active CLOB invocation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 396582a6-32db-44cd-b5dd-2d9d52f17a39
📒 Files selected for processing (1)
dexs/stratabook/index.ts
…ads) A CLOB instruction's log_messages includes nested program logs. The CLOB's own OrderFilled fires after all nested invocations complete, so it is the last 'Program data:' line in the instruction's log slice. Count remaining Program-data lines per log line (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) and decode only lines with exactly one remaining — nested programs' tag-3 payloads are rejected instead of miscounted as fills.
|
Addressed the emitter-binding finding (commit 89325d6): the fills CTE now decodes only the CLOB program's own event. Since the CLOB's OrderFilled fires AFTER all nested CPI invocations complete (verified on live mainnet fills), it is always the LAST Validated locally: sqlglot Trino-dialect parse + column resolution against the Dune schema for both tables, plus a functional simulation of the window logic (nested tag-3 payload REJECTED, CLOB OrderFilled ACCEPTED). ts-check passes. Current state of the query: |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
The stratabook adapter exports: |
|
@limeneris-beep it still seems to fail |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dexs/stratabook/index.ts`:
- Line 123: Update the fill_size expression in the query to use
varbinary_to_uint256 on the reversed eight-byte payload instead of
from_big_endian_64, preserving the existing base64 decoding, substring
extraction, and decimal cast so the little-endian u64 is interpreted as
unsigned.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: eafbe3de-2784-4f1d-aa18-6c0f5cd57518
📒 Files selected for processing (1)
dexs/stratabook/index.ts
from_big_endian_64 returns a signed BIGINT; a u64 fill_size above 2^63-1 would wrap negative. varbinary_to_uint256 (DuneSQL) interprets the 8-byte little-endian payload as unsigned big-endian, then the DECIMAL(38,0) cast preserves exact magnitude.
|
Addressed the fill_size sign finding (commit 66bd86e): the decode now uses Validated: sqlglot Trino-dialect parse + column resolution passes, ts-check passes. |
|
@coderabbitai review |
|
|
The stratabook adapter exports: |
…base64 character' Dune's log_messages can contain 'Program data:' lines that are NOT valid base64 (programs can log arbitrary text with that prefix; control chars survive into the stored array). Trino's from_base64 is strict and throws, killing the whole query — Node's Buffer tolerated it silently, which is why local RPC-log testing missed it. Decode once via try(from_base64(...)) (NULL on invalid input), filter on payload IS NOT NULL, and count only decodable lines for the emitter-binding window.
|
Fixed — the screenshot gave it away. The query was dying on Root cause: Dune's Fix (commit Validated:
Please re-run when you get a chance — if anything else surfaces, the Dune execution ID from the error ( |
|
@coderabbitai review |
|
|
The stratabook adapter exports: |
|
@coderabbitai review |
|
|
The stratabook adapter exports: |
|
@limeneris-beep thanks for the PR |

Adds the Stratabook volume, fees, and revenue adapter for Solana.
Protocol: Stratabook (Strata DEX) — fully on-chain CLOB on Solana with three execution layers, all settled by the same CLOB program
strataZWURmW6bzMWpkLCAFxNFrQXCNSE9cSmBmdPgP:Volume: parsed from on-chain
OrderFilledevents (sol_log_data, 100-byte payload) — tag 3,fill_sizeat bytes 81-89,settle_price89-97,source97. Sum of base-side fill sizes, USD-priced by DefiLlama. No warehouse dependency.Fees/Revenue: taker fee (
Market.taker_fee_bps, read live from market accounts) on all fills; maker rebate ships 0 and is not paid; supply-side revenue 0 (no LP incentives).Chain: Solana · Category: Dexs · Start: 2026-08-09 (first on-chain activity)
Methodology and full event layout documented in the adapter header comment.