Skip to content

feat(trades): add token trades endpoint#105

Merged
graphite-app[bot] merged 1 commit into
mainfrom
feature/rai-522-add-trades-token-endpoint
May 13, 2026
Merged

feat(trades): add token trades endpoint#105
graphite-app[bot] merged 1 commit into
mainfrom
feature/rai-522-add-trades-token-endpoint

Conversation

@findolor
Copy link
Copy Markdown
Collaborator

@findolor findolor commented May 12, 2026

Dependent PRs

  • Depends on rainlanguage/raindex#2570 for SDK getTrades token filtering support. This PR should not merge until that raindex PR lands and the submodule pointer is mergeable.

Summary

  • Adds GET /v1/trades/token/{address} for paginated trades involving a token address.
  • Wires the new route through the existing TradesDataSource abstraction and the raindex SDK get_trades token filters.
  • Reuses the shared trades list response shape used by owner-based trades, including pagination metadata and time filtering.
  • Refactors the owner trades route to share pagination and trade mapping helpers with the new token route.
  • Updates trade test mocks for the expanded TradesDataSource trait.
  • Updates order type detection for the raindex parsed meta variant rename from DotrainGuiStateV1 to OrderBuilderStateV1.
  • Bumps the rain.orderbook submodule to the SDK commit with token-filtered getTrades support.

Linear: RAI-526

Behavior

The new endpoint accepts the same pagination/time query parameters as GET /v1/trades/{address}:

GET /v1/trades/token/{tokenAddress}?page=1&pageSize=20&startTime=...&endTime=...

It returns trades where the token appears on either side of the trade by passing the token as both an input-token and output-token filter to the SDK.

Notes

  • The current raindex local DB query path is still the baseline implementation. In local benchmarking, high-volume token queries are around four seconds for pageSize=50; materialized trade read tables should be handled as a separate SDK/local DB optimization.
  • The unimplemented!() additions are test-only mock methods required by the expanded TradesDataSource trait; they are not production route code.

Verification

  • nix develop -c cargo check
  • nix develop -c cargo test
  • nix develop -c cargo fmt
  • nix develop -c rainix-rs-static

rainix-rs-static passes with pre-existing dead-code warnings in src/cache.rs.

Summary by CodeRabbit

  • New Features

    • Added a new API endpoint to retrieve trades by token address with pagination support.
  • Documentation

    • Updated OpenAPI documentation to include the new trades endpoint.
  • Refactor

    • Refactored trade handlers to use shared helper functions for pagination and response construction.
    • Updated order type detection logic to use revised metadata structure.
  • Chores

    • Updated rain.orderbook dependency to latest version.

Review Change Stack

@linear
Copy link
Copy Markdown

linear Bot commented May 12, 2026

RAI-522

RAI-526

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a13dc35d-1b21-4ae9-8f79-853a638ef725

📥 Commits

Reviewing files that changed from the base of the PR and between 500f191 and 54e38c6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • lib/rain.orderbook
  • src/main.rs
  • src/routes/order/get_order.rs
  • src/routes/trades/get_by_address.rs
  • src/routes/trades/get_by_token.rs
  • src/routes/trades/get_by_tx.rs
  • src/routes/trades/mod.rs
✅ Files skipped from review due to trivial changes (2)
  • lib/rain.orderbook
  • src/main.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/routes/trades/get_by_tx.rs
  • src/routes/order/get_order.rs
  • src/routes/trades/get_by_address.rs
  • src/routes/trades/mod.rs
  • src/routes/trades/get_by_token.rs

📝 Walkthrough

Walkthrough

Adds GET /v1/trades/token/{address} with pagination and auth, extends TradesDataSource with token-based queries, refactors shared pagination/response helpers used by trades handlers, registers the new route in OpenAPI, updates test mocks, and changes DCA detection to use OrderBuilderStateV1 metadata.

Changes

Trades-by-Token Route

Layer / File(s) Summary
TradesDataSource trait and Raindex implementation
src/routes/trades/mod.rs
Adds get_trades_for_token and implements Raindex-backed token queries with GetTradesFilters and explicit page/page_size handling.
Pagination and response helpers
src/routes/trades/mod.rs, src/routes/trades/get_by_address.rs
Adds trades_pagination_params and build_trades_list_response; refactors process_get_trades_by_address to use them and updates mocks in tests.
Trades-by-token route handler and tests
src/routes/trades/get_by_token.rs
Adds GET /v1/trades/token/{address} Rocket handler, process_get_trades_by_token, Raindex wiring, and tests for success, empty results, upstream error, missing auth (401), and invalid address (422).
Integration and route registration
src/main.rs, lib/rain.orderbook, src/routes/trades/get_by_tx.rs
Registers the new route in OpenAPI and Rocket routes(), updates rain.orderbook submodule SHA, and extends test mocks to satisfy the extended trait.

Order Type Classification

Layer / File(s) Summary
DCA metadata detection update
src/routes/order/get_order.rs
determine_order_type now matches ParsedMeta::OrderBuilderStateV1 and classifies OrderType::Dca when builder_state.selected_deployment contains "dca" (case-insensitive).

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RocketHandler
  participant RaindexTradesDataSource
  participant RaindexClient
  Client->>RocketHandler: GET /v1/trades/token/{address} + Authorization + pagination
  RocketHandler->>RaindexTradesDataSource: get_trades_for_token(token, page, page_size, time_filter)
  RaindexTradesDataSource->>RaindexClient: query trades with GetTradesFilters + page/page_size
  RaindexClient-->>RaindexTradesDataSource: RaindexTradesListResult
  RaindexTradesDataSource-->>RocketHandler: mapped trades list
  RocketHandler-->>Client: 200 JSON (TradesByAddressResponse)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • JuaniRios
  • 0xgleb
  • hardyjosh

Poem

🐰 I hopped through trades and bound the page,
Token routes now listen, tests engage,
DCA reads builder-state anew,
Routes registered, docs updated too—hippity-hue!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(trades): add token trades endpoint' directly and clearly summarizes the main change: adding a new token trades API endpoint.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/rai-522-add-trades-token-endpoint

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Collaborator Author

findolor commented May 12, 2026


How to use the Graphite Merge Queue

Add the label add-to-gt-merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@findolor findolor self-assigned this May 12, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/routes/order/get_order.rs (1)

70-83: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add test coverage for DCA order type detection.

The DCA detection logic was modified but lacks test coverage. The only existing test (test_determine_order_type_solver_default) verifies the fallback case, not the new OrderBuilderStateV1 variant matching.

📝 Suggested test additions

Add tests to verify DCA detection with various deployment names:

#[rocket::async_test]
async fn test_determine_order_type_dca_lowercase() {
    let mut order = mock_order();
    // Add OrderBuilderStateV1 metadata with "dca" in selected_deployment
    // (This requires extending the mock to include parsed_meta)
    assert_eq!(determine_order_type(&order), OrderType::Dca);
}

#[rocket::async_test]
async fn test_determine_order_type_dca_uppercase() {
    let mut order = mock_order();
    // Add OrderBuilderStateV1 metadata with "DCA" in selected_deployment
    assert_eq!(determine_order_type(&order), OrderType::Dca);
}

#[rocket::async_test]
async fn test_determine_order_type_dca_mixed_case() {
    let mut order = mock_order();
    // Add OrderBuilderStateV1 metadata with "my-DCA-strategy" in selected_deployment
    assert_eq!(determine_order_type(&order), OrderType::Dca);
}

#[rocket::async_test]
async fn test_determine_order_type_non_dca() {
    let mut order = mock_order();
    // Add OrderBuilderStateV1 metadata with "limit-order" in selected_deployment
    assert_eq!(determine_order_type(&order), OrderType::Solver);
}
🤖 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 `@src/routes/order/get_order.rs` around lines 70 - 83, Add unit tests for
determine_order_type to cover the new OrderBuilderStateV1 branch: create mock
orders (using mock_order) whose parsed_meta() returns a
ParsedMeta::OrderBuilderStateV1 with builder_state.selected_deployment set to
values containing "dca" in lowercase, uppercase, and mixed case (e.g., "dca",
"DCA", "my-DCA-strategy") and assert determine_order_type(&order) ==
OrderType::Dca; also add a negative test where selected_deployment is
non‑matching (e.g., "limit-order") and assert OrderType::Solver. Ensure tests
reference determine_order_type, RaindexOrder, ParsedMeta::OrderBuilderStateV1,
and OrderType so they exercise the new detection logic.
🤖 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 `@src/routes/order/get_order.rs`:
- Around line 70-83: Add unit tests for determine_order_type to cover the new
OrderBuilderStateV1 branch: create mock orders (using mock_order) whose
parsed_meta() returns a ParsedMeta::OrderBuilderStateV1 with
builder_state.selected_deployment set to values containing "dca" in lowercase,
uppercase, and mixed case (e.g., "dca", "DCA", "my-DCA-strategy") and assert
determine_order_type(&order) == OrderType::Dca; also add a negative test where
selected_deployment is non‑matching (e.g., "limit-order") and assert
OrderType::Solver. Ensure tests reference determine_order_type, RaindexOrder,
ParsedMeta::OrderBuilderStateV1, and OrderType so they exercise the new
detection logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6d605ad3-7b27-4b83-becc-fdfe7237c1af

📥 Commits

Reviewing files that changed from the base of the PR and between c0e9b91 and 500f191.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • lib/rain.orderbook
  • src/main.rs
  • src/routes/order/get_order.rs
  • src/routes/trades/get_by_address.rs
  • src/routes/trades/get_by_token.rs
  • src/routes/trades/get_by_tx.rs
  • src/routes/trades/mod.rs

findolor added a commit that referenced this pull request May 12, 2026
## Chained PRs

- Stacked on [#106](#106) for the taker trades endpoint.
- Also follows [#105](#105) for the token trades endpoint.

## Dependent PRs

- Depends on [rainlanguage/raindex#2572](rainlanguage/raindex#2572) ([Graphite](https://app.graphite.com/github/pr/rainlanguage/raindex/2572)) for SDK `getTradesByOrderHashes` support, local DB order-hash batching, and grouped results. This PR should not merge until that raindex PR lands and the submodule pointer is mergeable.

## Summary

- Adds `POST /v1/trades/query` for batch order-hash trade lookup.
- Defines request/response DTOs for `orderHashes` input and `tradesByOrderHash` grouped output.
- Includes every requested hash in the response through the SDK grouping behavior, including hashes with no trades.
- Validates order hashes with existing API error handling and returns `400` for invalid hash input.
- Wires the route through the existing trades module, auth, rate limiting, tracing span propagation, and OpenAPI registration.
- Uses the raindex SDK batch order-hash API directly; there is no API-side query workaround.
- Reuses the shared trade list mapper for each grouped trade entry.
- Bumps the `rain.orderbook` submodule to the SDK commit with batch order-hash trade lookup support.

Linear: RAI-528

## Behavior

The new endpoint accepts a JSON body:

```json
{
  "orderHashes": [
    "0x4a051ad4567935a5a0570b3e2e77714c44405bb58e5b83e3cc484de1cee0747e"
  ],
  "startTime": 1718452800,
  "endTime": 1718539200
}
```

It returns trades grouped by requested order hash:

```json
{
  "tradesByOrderHash": [
    {
      "orderHash": "0x4a051ad4567935a5a0570b3e2e77714c44405bb58e5b83e3cc484de1cee0747e",
      "trades": []
    }
  ],
  "totalCount": 0
}
```

## Local DB Smoke Test

After clearing the local raindex DB and waiting for the Base local source to become ready, the endpoint used local DB only:

```text
local_chain_ids_count=1
subgraph_chain_ids_count=0
```

Single-order smoke test:

- Request: one real order hash plus one zero hash.
- Result: real hash returned `50` trades; zero hash returned an empty `trades` array.
- HTTP total: `0.415652s`.
- SDK local fetch: `29ms`; SDK total: `161ms`.

Heavy response stress test using the highest-trade order hashes in the local DB:

- Top 10 order hashes: `3,790` trades, `2.12 MB` response, HTTP total `11.20s`.
- Top 20 order hashes: `4,596` trades, `2.57 MB` response, HTTP total `13.50s`.
- Top 20 SQL fetch was `930ms`; full SDK grouping/materialization was `13211ms`; full API request was `13495ms`.

The heavy case is dominated by materializing, grouping, mapping, and serializing thousands of full trade objects rather than by SQL lookup.

## Notes

- The `unimplemented!()` additions are test-only mock methods required by the expanded `TradesDataSource` trait; they are not production route code.
- Empty `orderHashes` currently returns an empty grouped result, matching the SDK behavior.

## Verification

- `nix develop -c cargo fmt`
- `nix develop -c cargo check`
- `nix develop -c cargo test routes::trades::get_by_order_hashes`
- `nix develop -c cargo test`
- `nix develop -c rainix-rs-static`

`rainix-rs-static` passes with pre-existing dead-code warnings in `src/cache.rs`.
@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented May 13, 2026

Merge activity

## Dependent PRs

- Depends on [rainlanguage/raindex#2570](rainlanguage/raindex#2570) for SDK `getTrades` token filtering support. This PR should not merge until that raindex PR lands and the submodule pointer is mergeable.

## Summary

- Adds `GET /v1/trades/token/{address}` for paginated trades involving a token address.
- Wires the new route through the existing `TradesDataSource` abstraction and the raindex SDK `get_trades` token filters.
- Reuses the shared trades list response shape used by owner-based trades, including pagination metadata and time filtering.
- Refactors the owner trades route to share pagination and trade mapping helpers with the new token route.
- Updates trade test mocks for the expanded `TradesDataSource` trait.
- Updates order type detection for the raindex parsed meta variant rename from `DotrainGuiStateV1` to `OrderBuilderStateV1`.
- Bumps the `rain.orderbook` submodule to the SDK commit with token-filtered `getTrades` support.

Linear: RAI-526

## Behavior

The new endpoint accepts the same pagination/time query parameters as `GET /v1/trades/{address}`:

```text
GET /v1/trades/token/{tokenAddress}?page=1&pageSize=20&startTime=...&endTime=...
```

It returns trades where the token appears on either side of the trade by passing the token as both an input-token and output-token filter to the SDK.

## Notes

- The current raindex local DB query path is still the baseline implementation. In local benchmarking, high-volume token queries are around four seconds for `pageSize=50`; materialized trade read tables should be handled as a separate SDK/local DB optimization.
- The `unimplemented!()` additions are test-only mock methods required by the expanded `TradesDataSource` trait; they are not production route code.

## Verification

- `nix develop -c cargo check`
- `nix develop -c cargo test`
- `nix develop -c cargo fmt`
- `nix develop -c rainix-rs-static`

`rainix-rs-static` passes with pre-existing dead-code warnings in `src/cache.rs`.
@graphite-app graphite-app Bot force-pushed the feature/rai-522-add-trades-token-endpoint branch from 500f191 to 54e38c6 Compare May 13, 2026 17:10
graphite-app Bot pushed a commit that referenced this pull request May 13, 2026
## Chained PRs

- Stacked on [#105](#105) for the token trades endpoint.

## Dependent PRs

- Depends on [rainlanguage/raindex#2571](rainlanguage/raindex#2571) for SDK `getTrades` taker filtering, local DB predicate pushdown, sender-time indexes, and local query tracing. This PR should not merge until that raindex PR lands and the submodule pointer is mergeable.

## Summary

- Adds `GET /v1/trades/taker/{address}` for paginated trades by taker address.
- Wires the endpoint through the existing trades route module, OpenAPI registration, auth, rate limiting, tracing span propagation, and shared trades response mapping.
- Uses the raindex SDK `get_trades` taker filter directly with pagination and time filtering; there is no API-side query workaround.
- Clones the shared `RaindexClient` before awaiting the SDK call so the raindex provider read lock is not held during fetch/count work.
- Adds focused tests for successful taker queries, empty results, SDK errors, auth failure, invalid address handling, and route registration.
- Bumps the `rain.orderbook` submodule to the SDK commit with taker-filtered `getTrades` support and local DB query tracing.

Linear: RAI-530

## Behavior

The new endpoint accepts the same pagination/time query parameters as the existing trade list endpoints:

```text
GET /v1/trades/taker/{takerAddress}?page=1&pageSize=20&startTime=...&endTime=...
```

It returns trades whose taker/sender matches the path address and includes the shared trade list pagination metadata.

## Local DB Smoke Test

After resetting the local raindex DB and waiting for `/health/detailed` to report Base as active and ready, the endpoint used local DB only:

```text
local_chain_ids_count=1
subgraph_chain_ids_count=0
```

Measured locally against taker `0x55f3412d51bbe48255a286189848a151236c0307`:

- `pageSize=3`: 3 rows, `totalTrades=1676`, HTTP total `1.596s`; SDK fetch `667ms`, count `662ms`, total `1343ms`.
- `pageSize=50`: 50 rows, `totalTrades=1676`, HTTP total `1.726s`; SDK fetch `675ms`, count `651ms`, total `1477ms`.

## Verification

- `nix develop -c cargo check`
- `nix develop -c cargo test routes::trades::get_by_taker`
- `nix develop -c cargo test`
- `nix develop -c cargo fmt`
- `nix develop -c rainix-rs-static`

`rainix-rs-static` passes with pre-existing dead-code warnings in `src/cache.rs`.

<!-- codesmith:footer -->
---
<a href="https://app.blacksmith.sh/ST0x-Technology/codesmith/st0x.rest.api/pr/106"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img alt="View in Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith</code> with what you need.</sup>

- [ ] Let Codesmith autofix CI failures and bot reviews
<!-- /codesmith:footer -->
graphite-app Bot pushed a commit that referenced this pull request May 13, 2026
## Chained PRs

- Stacked on [#106](#106) for the taker trades endpoint.
- Also follows [#105](#105) for the token trades endpoint.

## Dependent PRs

- Depends on [rainlanguage/raindex#2572](rainlanguage/raindex#2572) ([Graphite](https://app.graphite.com/github/pr/rainlanguage/raindex/2572)) for SDK `getTradesByOrderHashes` support, local DB order-hash batching, and grouped results. This PR should not merge until that raindex PR lands and the submodule pointer is mergeable.

## Summary

- Adds `POST /v1/trades/query` for batch order-hash trade lookup.
- Defines request/response DTOs for `orderHashes` input and `tradesByOrderHash` grouped output.
- Includes every requested hash in the response through the SDK grouping behavior, including hashes with no trades.
- Validates order hashes with existing API error handling and returns `400` for invalid hash input.
- Wires the route through the existing trades module, auth, rate limiting, tracing span propagation, and OpenAPI registration.
- Uses the raindex SDK batch order-hash API directly; there is no API-side query workaround.
- Reuses the shared trade list mapper for each grouped trade entry.
- Bumps the `rain.orderbook` submodule to the SDK commit with batch order-hash trade lookup support.

Linear: RAI-528

## Behavior

The new endpoint accepts a JSON body:

```json
{
  "orderHashes": [
    "0x4a051ad4567935a5a0570b3e2e77714c44405bb58e5b83e3cc484de1cee0747e"
  ],
  "startTime": 1718452800,
  "endTime": 1718539200
}
```

It returns trades grouped by requested order hash:

```json
{
  "tradesByOrderHash": [
    {
      "orderHash": "0x4a051ad4567935a5a0570b3e2e77714c44405bb58e5b83e3cc484de1cee0747e",
      "trades": []
    }
  ],
  "totalCount": 0
}
```

## Local DB Smoke Test

After clearing the local raindex DB and waiting for the Base local source to become ready, the endpoint used local DB only:

```text
local_chain_ids_count=1
subgraph_chain_ids_count=0
```

Single-order smoke test:

- Request: one real order hash plus one zero hash.
- Result: real hash returned `50` trades; zero hash returned an empty `trades` array.
- HTTP total: `0.415652s`.
- SDK local fetch: `29ms`; SDK total: `161ms`.

Heavy response stress test using the highest-trade order hashes in the local DB:

- Top 10 order hashes: `3,790` trades, `2.12 MB` response, HTTP total `11.20s`.
- Top 20 order hashes: `4,596` trades, `2.57 MB` response, HTTP total `13.50s`.
- Top 20 SQL fetch was `930ms`; full SDK grouping/materialization was `13211ms`; full API request was `13495ms`.

The heavy case is dominated by materializing, grouping, mapping, and serializing thousands of full trade objects rather than by SQL lookup.

## Notes

- The `unimplemented!()` additions are test-only mock methods required by the expanded `TradesDataSource` trait; they are not production route code.
- Empty `orderHashes` currently returns an empty grouped result, matching the SDK behavior.

## Verification

- `nix develop -c cargo fmt`
- `nix develop -c cargo check`
- `nix develop -c cargo test routes::trades::get_by_order_hashes`
- `nix develop -c cargo test`
- `nix develop -c rainix-rs-static`

`rainix-rs-static` passes with pre-existing dead-code warnings in `src/cache.rs`.
@graphite-app graphite-app Bot merged commit 54e38c6 into main May 13, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants