Skip to content

Add chain id and orderbook address to local db logic#2278

Merged
findolor merged 18 commits intomainfrom
local-db-chain-id-orderbook-address
Nov 10, 2025
Merged

Add chain id and orderbook address to local db logic#2278
findolor merged 18 commits intomainfrom
local-db-chain-id-orderbook-address

Conversation

@findolor
Copy link
Copy Markdown
Collaborator

@findolor findolor commented Oct 29, 2025

Motivation

See issues:

Solution

  • Add chain id and orderbook address fields to every local db table
  • Update queries to utilize the new fields
  • Update query builders to use the new fields
  • Update the existing call sites to work with new fields
  • Update existing tests

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Summary by CodeRabbit

  • New Features

    • Added support for managing multiple orderbooks within the same blockchain network.
    • Enhanced local database organization with improved composite key structure for better data scoping and isolation.
  • Bug Fixes

    • Improved transaction hash handling for more reliable data processing.
  • Database Schema Updates

    • Updated table structures to support per-orderbook data organization across all event and metadata tables.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 29, 2025

Walkthrough

This PR introduces OrderbookIdentifier as a unified type combining chain_id and orderbook_address, propagating it through local_db sync/query APIs, database schema, and raindex_client methods. The changes include database schema updates with composite primary keys, conversion of transaction_hash from String to Bytes, comprehensive signature updates across query builders and pipeline components, and field renames (e.g., address to token_address) to reflect new schema structure.

Changes

Cohort / File(s) Summary
OrderbookIdentifier Type Definition
crates/common/src/local_db/mod.rs
New public struct with chain_id: u32 and orderbook_address: Address fields, plus new() constructor.
Database Schema
crates/common/src/local_db/query/create_tables/query.sql
Updated all tables (sync_status, raw_events, deposits, withdrawals, order_events, order_ios, take_orders, take_order_contexts, context_values, clear_v3_events, after_clear_v2_events, meta_events, erc20_tokens, interpreter_store_sets) to add chain_id and orderbook_address columns; modified primary/composite keys; updated indices and foreign keys.
Last Synced Block Query
crates/common/src/local_db/query/fetch_last_synced_block/mod.rs, query.sql
Updated SyncStatusResponse struct to include chain_id and orderbook_address fields; changed fetch_last_synced_block_stmt() to accept &OrderbookIdentifier parameter; added parameterized WHERE clause filtering.
Store Addresses Query
crates/common/src/local_db/query/fetch_store_addresses/mod.rs, query.sql
Updated fetch_store_addresses_stmt() to accept &OrderbookIdentifier; added parameterized SQL with chain_id and orderbook_address filters.
Target Watermark Query
crates/common/src/local_db/query/fetch_target_watermark/mod.rs, query.sql
Renamed fetch_target_watermark_stmt() to accept &OrderbookIdentifier instead of separate chain_id and Address; updated WHERE clause for case-insensitive address matching.
ERC20 Tokens Query
crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs, query.sql
Updated Erc20TokenRow to rename address to orderbook_address and add token_address: Address; changed build_fetch_stmt() to accept &OrderbookIdentifier and &[Address] for addresses.
Order Trades Queries
crates/common/src/local_db/query/fetch_order_trades/mod.rs, query.sql, fetch_order_trades_count/mod.rs, query.sql
Updated both functions to accept &OrderbookIdentifier; expanded SQL joins/filters to use chain_id and orderbook_address in all ON/WHERE clauses with parameterized values.
Orders Query
crates/common/src/local_db/query/fetch_orders/mod.rs, query.sql
Updated build_fetch_orders_stmt() to accept &OrderbookIdentifier; added parameterized chain_id and orderbook_address to all joins; shifted active-filter parameter index.
Vault Queries
crates/common/src/local_db/query/fetch_vault/mod.rs, query.sql, fetch_vaults/mod.rs, query.sql, fetch_vault_balance_changes/mod.rs, query.sql
Updated all three to accept &OrderbookIdentifier; expanded SQL joins to include chain_id and orderbook_address filtering; adjusted parameter indices (?1/?2 now map to chain_id/orderbook_address).
Update Last Synced Block
crates/common/src/local_db/query/update_last_synced_block/mod.rs, query.sql
Changed from UPDATE to UPSERT; added ob_id: &OrderbookIdentifier parameter; expanded SQL to insert chain_id and orderbook_address with ON CONFLICT composite key.
Event Decoding
crates/common/src/local_db/decode.rs
Changed DecodedEventData::transaction_hash from String to Bytes; updated decoding logic to construct Bytes via Bytes::from_str().
Event Insert Logic
crates/common/src/local_db/insert.rs
Updated EventContext struct to remove lifetime and add ob_id: OrderbookIdentifier and transaction_hash: Bytes; added ob_id parameter to decoded_events_to_statements(), raw_events_to_statements(), and all per-event SQL generators; expanded SQL parameter lists to prepend chain_id and orderbook_address.
Local DB Storage/Sync
crates/common/src/local_db/storage.rs, sync.rs
Updated fetch_last_synced(), fetch_existing_store_addresses(), fetch_existing_tokens() to accept &OrderbookIdentifier; renamed Erc20TokenRow.address to token_address.
Token Metadata Preparation
crates/common/src/local_db/sync/token.rs
Changed prepare_token_metadata() to accept ob_id: &OrderbookIdentifier instead of chain_id; updated token address field references.
Sync Runner
crates/cli/src/commands/local_db/sync/runner/apply.rs, mod.rs, window.rs, data_source.rs
Updated PrepareSqlParams to use ob_id: OrderbookIdentifier instead of chain_id; threaded ob_id through all SQL builders; updated mock implementations and test scaffolding.
Local DB Pipeline Adapters
crates/common/src/local_db/pipeline/adapters/apply.rs, tokens.rs, window.rs, bootstrap.rs
Updated Erc20TokenRow fields; changed pipeline trait signatures to accept &OrderbookIdentifier; updated build_batch(), compute(), load_existing() methods.
Pipeline Core
crates/common/src/local_db/pipeline/mod.rs
Removed TargetKey struct; updated SyncOutcome to include ob_id: &'a OrderbookIdentifier; updated trait signatures for WindowPipeline, TokensPipeline, ApplyPipeline.
RaindexClient Queries
crates/common/src/raindex_client/local_db/query/fetch_erc20_tokens_by_addresses.rs, fetch_last_synced_block.rs, fetch_order_trades.rs, fetch_order_trades_count.rs, fetch_orders.rs, fetch_store_addresses.rs, fetch_vault.rs, fetch_vault_balance_changes.rs, fetch_vaults.rs, update_last_synced_block.rs
Updated all public async query functions to accept &OrderbookIdentifier as first parameter (after executor); adjusted wasm test bindings.
RaindexClient Orders/Trades/Vaults
crates/common/src/raindex_client/orders.rs, trades.rs, vaults.rs, order_quotes.rs, remove_orders.rs
Updated all high-level methods to construct and accept &OrderbookIdentifier for per-orderbook fetching; added multi-orderbook iteration in applicable code paths.
Vault Deltas View
crates/common/src/local_db/views/vault_deltas.sql
Added chain_id and orderbook_address columns to all UNION branches; expanded JOIN conditions to use chain_id and case-insensitive orderbook_address matching.
CLI Bootstrap
crates/cli/src/commands/local_db/pipeline/bootstrap.rs
Updated BootstrapConfig to use ob_id: OrderbookIdentifier instead of target_key: TargetKey.
RaindexClient Bootstrap
crates/common/src/raindex_client/local_db/pipeline/bootstrap.rs
Replaced TargetKey with OrderbookIdentifier in pipeline config and is_fresh_db logic.
Webapp Local DB Sync
packages/webapp/src/lib/services/startLocalDbSync.ts, src/routes/db-playground/+page.svelte
Added optional orderbookAddress: Hex field to sync options; updated getSyncStatus() calls to include chainId and orderbookAddress parameters.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Pipeline as Sync Pipeline
    participant Query as Query Builder
    participant DB as Database
    participant Insert as Insert Logic

    App->>Pipeline: initiate_sync(chain_id, orderbook_addr)
    Pipeline->>Pipeline: create OrderbookIdentifier
    
    Pipeline->>Query: fetch_last_synced_block_stmt(ob_id)
    Query->>DB: SELECT WHERE chain_id=?1 AND orderbook_addr=?2
    DB-->>Query: last_block
    Query-->>Pipeline: last_block
    
    Pipeline->>Pipeline: fetch decoded_events
    
    Pipeline->>Insert: decoded_events_to_statements(ob_id, events, decimals)
    Insert->>Insert: build EventContext with ob_id
    Insert->>Insert: generate SQL with chain_id + orderbook_addr prefix
    Insert-->>Pipeline: SqlStatementBatch
    
    Pipeline->>Query: build_update_last_synced_block_stmt(ob_id, new_block)
    Query->>DB: UPSERT sync_status WHERE (chain_id, orderbook_addr)
    
    Pipeline->>DB: execute batch
    DB-->>Pipeline: ✓ success
    
    Pipeline-->>App: sync_complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Database schema migration: Composite primary key changes across 15+ tables with cascading foreign key updates (create_tables/query.sql and all related indices)
  • EventContext/event insertion flow: Removed lifetimes and added OrderbookIdentifier propagation through all event generators (insert.rs affects all event types)
  • Query parameter binding: New parameterized SQL with shifted placeholder indices (?1/?2 now reserved for chain_id/orderbook_address) in 15+ query files—potential for off-by-one errors
  • RaindexClient multi-orderbook iteration: New per-orderbook loops in orders.rs and vaults.rs that iterate fetches by chain/orderbook; verify correctness of aggregation logic
  • Trait method signature consistency: SyncDataSource, WindowPipeline, TokensPipeline, ApplyPipeline trait changes—ensure all implementations updated
  • Erc20TokenRow field rename (address→token_address, +orderbook_address): Track all usages to ensure address parsing and field access are correct across pipeline adapters and query modules

Possibly related issues

Possibly related PRs

Suggested labels

test, rust

Suggested reviewers

  • 0xgleb
  • hardyjosh

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding chain id and orderbook address fields to local db logic, which aligns with the core objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 96.97% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch local-db-chain-id-orderbook-address

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

@findolor
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 29, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 28

Caution

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

⚠️ Outside diff range comments (14)
crates/common/src/local_db/query/fetch_vaults/query.sql (1)

10-46: Remove ORDER BY non-selected column for deterministic DISTINCT results

SQLite allows ORDER BY expressions that are not in the SELECT list for DISTINCT queries. However, ordering by oe.order_hash while deduplicating on the item column creates non-deterministic results. Order by the selected alias item instead to ensure deterministic output aligned with the deduplication key:

-      ORDER BY oe.order_hash
+      ORDER BY item

Apply to both input and output subqueries (lines 10-46 and 48-84).

crates/common/src/local_db/pipeline/adapters/window.rs (1)

77-82: Minor: avoid variable shadowing for clarity (and clippy pedantic)

target shadows the function parameter name. Rename to end_block to avoid confusion.

-        let requested_target = cfg.window_overrides.end_block.unwrap_or(safe_head);
-        let target = requested_target.min(safe_head);
-        Ok((start, target))
+        let requested_end = cfg.window_overrides.end_block.unwrap_or(safe_head);
+        let end_block = requested_end.min(safe_head);
+        Ok((start, end_block))
crates/common/src/local_db/query/fetch_order_trades/mod.rs (1)

1-6: Optional: normalize address string if DB uses lowercase.

If the DB schema stores addresses normalized to lowercase, bind orderbook_address.to_string().to_lowercase() for consistency. Otherwise, keep as-is.

Also applies to: 68-80

crates/common/src/local_db/pipeline/adapters/tokens.rs (2)

24-36: Avoid lossy cast from u64 to u32 for chain_id

Casting u64 to u32 can truncate and will trigger clippy (with warnings denied). Either:

  • Make load_existing take chain_id: u32, or
  • Use u32::try_from(chain_id)? and propagate an error.

Example:

-    async fn load_existing<DB>(
+    async fn load_existing<DB>(
         &self,
         db: &DB,
-        chain_id: u64,
+        chain_id: u32,
         orderbook_address: Address,
         token_addrs_lower: &[Address],
     ) -> Result<Vec<Erc20TokenRow>, LocalDbError>
 ...
-        let Some(stmt) = build_fetch_stmt(chain_id as u32, orderbook_address, token_addrs_lower)?
+        let Some(stmt) = build_fetch_stmt(chain_id, orderbook_address, token_addrs_lower)?
         else {
             return Ok(vec![]);
         };

If the trait requires u64 elsewhere, prefer:

-        let Some(stmt) = build_fetch_stmt(chain_id as u32, orderbook_address, token_addrs_lower)?
+        let cid = u32::try_from(chain_id).map_err(|_| LocalDbError::CustomError("chain_id > u32".into()))?;
+        let Some(stmt) = build_fetch_stmt(cid, orderbook_address, token_addrs_lower)?

24-30: Arg naming: drop _lower suffix

token_addrs_lower is Address-typed, not lowercased strings. Rename to token_addrs for clarity.

crates/cli/src/commands/local_db/sync/runner/mod.rs (2)

356-370: Fix type of transaction_hash in test helpers (now Bytes, not String)

DecodedEventData.transaction_hash uses alloy::primitives::Bytes. Current literals ("0xabc"/"0xstore") will not compile. Update:

-    use alloy::primitives::{Address, FixedBytes, U256};
+    use alloy::primitives::{Address, Bytes, FixedBytes, U256};
...
-            transaction_hash: "0xabc".into(),
+            transaction_hash: Bytes::from_str("0xabc").unwrap(),
...
-            transaction_hash: "0xstore".into(),
+            transaction_hash: Bytes::from_str("0xdeadbeef").unwrap(),

140-153: Parse orderbook address once to avoid duplicate parsing

You parse Address::from_str(params.orderbook_address)? twice. Compute once and reuse:

-        let existing_stores = fetch_existing_store_addresses(
-            self.db_path,
-            params.chain_id,
-            Address::from_str(params.orderbook_address)?,
-        )
+        let ob_addr = Address::from_str(params.orderbook_address)?;
+        let existing_stores = fetch_existing_store_addresses(
+            self.db_path,
+            params.chain_id,
+            ob_addr,
+        )
         .await?;
...
-                orderbook_address: Address::from_str(params.orderbook_address)?,
+                orderbook_address: ob_addr,
crates/common/src/local_db/sync.rs (3)

70-77: Guard against empty range (start_block > latest_block).

BlockRange::inclusive will error if latest_block < start_block (e.g., when deployment_block is ahead of latest). Short‑circuit early and skip syncing in that case.

Apply this minimal guard:

-    let range = BlockRange::inclusive(start_block, latest_block)?;
+    if latest_block < start_block {
+        status.send(format!(
+            "No new blocks to sync: start={} > latest={}",
+            start_block, latest_block
+        ))?;
+        return Ok(());
+    }
+    let range = BlockRange::inclusive(start_block, latest_block)?;

94-97: Map store address parse errors to LocalDbError with context.

Address::from_str errors bubble via ? without context; prefer mapping to LocalDbError and include the offending string/index.

Use index-aware mapping:

-    let store_addresses: Vec<Address> = store_addresses_vec
-        .iter()
-        .map(|s| Address::from_str(s))
-        .collect::<Result<_, _>>()?;
+    let store_addresses: Vec<Address> = store_addresses_vec
+        .iter()
+        .enumerate()
+        .map(|(i, s)| Address::from_str(s).map_err(|e| {
+            LocalDbError::CustomError(format!("invalid store address at index {i}: {s} ({e})"))
+        }))
+        .collect::<Result<_, _>>()?;

342-346: Prefer explicit Bytes parsing in tests.

Use Bytes::from_str(...) instead of ".into()" for clarity and to avoid relying on implicit conversions that may change.

Example:

-transaction_hash: "0x10".into(),
+transaction_hash: Bytes::from_str("0x10").unwrap(),

Also applies to: 641-647, 661-667, 681-687

crates/cli/src/commands/local_db/sync/data_source.rs (1)

95-103: Parse orderbook_address with context.

Add context to Address::from_str failure to aid debugging.

-Address::from_str(orderbook_address)?,
+Address::from_str(orderbook_address)
+    .with_context(|| format!("invalid orderbook address: {orderbook_address}"))?,
crates/common/src/local_db/insert.rs (3)

509-551: Bug: RemoveOrderV3 event_type is in the wrong VALUES position.

'RemoveOrderV3' currently occupies the log_index slot; values are shifted/misaligned.

Fix VALUES ordering to match columns (put constant after log_index):

- ) VALUES (
-    ?1,
-    ?2,
-    ?3,
-    ?4,
-    ?5,
-    'RemoveOrderV3',
-    ?6,
-    ?7,
-    ?8,
-    ?9,
-    ?10,
-    ?11
+ ) VALUES (
+    ?1,
+    ?2,
+    ?3,
+    ?4,
+    ?5,
+    ?6,
+    'RemoveOrderV3',
+    ?7,
+    ?8,
+    ?9,
+    ?10,
+    ?11

771-841: Bug: clear_v3_events has 21 columns but only 20 placeholders.

VALUES list stops at ?20; last column (bob_output_vault_id) never bound. Runtime bind error risk.

Add the missing placeholder:

 ) VALUES (
     ?1,
     ?2,
     ?3,
     ?4,
     ?5,
     ?6,
     ?7,
     ?8,
     ?9,
     ?10,
     ?11,
     ?12,
     ?13,
     ?14,
     ?15,
     ?16,
     ?17,
     ?18,
-    ?19,
-    ?20
+    ?19,
+    ?20,
+    ?21
 );

Update the unit test to assert the new highest placeholder:

-assert!(statement.sql().contains("?20"));
+assert!(statement.sql().contains("?21"));

154-160: Multiple instances of .to_string() on Address/Bytes types found; should use hex::encode_prefixed() for consistency.

The review correctly identifies real instances where hex encoding should be explicit:

  • Line 240, 286: orderbook_address.to_string() in SQL params
  • Lines 369, 426, 483, 542, 606, 656, 701, 822, 887, 935, 984, 1025, 1041: transaction_hash.to_string() in SQL params
  • Line 154-160: eprintln using event.transaction_hash directly instead of hex-encoded

The codebase imports alloy::hex and already uses hex::encode_prefixed() elsewhere (lines 314, 981, 986+), establishing inconsistent encoding patterns.

Unable to verify clippy output (nix unavailable in sandbox), but please manually run:

nix develop -c cargo clippy --workspace --all-targets --all-features -D warnings

to confirm no new warnings are introduced by applying the suggested refactors across all listed line ranges.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2a4dd6 and 52311f1.

📒 Files selected for processing (52)
  • crates/cli/src/commands/local_db/sync/data_source.rs (2 hunks)
  • crates/cli/src/commands/local_db/sync/runner/apply.rs (15 hunks)
  • crates/cli/src/commands/local_db/sync/runner/mod.rs (12 hunks)
  • crates/cli/src/commands/local_db/sync/runner/window.rs (5 hunks)
  • crates/cli/src/commands/local_db/sync/storage.rs (9 hunks)
  • crates/cli/src/commands/local_db/sync/token.rs (5 hunks)
  • crates/common/src/local_db/decode.rs (4 hunks)
  • crates/common/src/local_db/insert.rs (62 hunks)
  • crates/common/src/local_db/mod.rs (3 hunks)
  • crates/common/src/local_db/pipeline/adapters/apply.rs (24 hunks)
  • crates/common/src/local_db/pipeline/adapters/tokens.rs (5 hunks)
  • crates/common/src/local_db/pipeline/adapters/window.rs (5 hunks)
  • crates/common/src/local_db/pipeline/traits.rs (1 hunks)
  • crates/common/src/local_db/query/create_tables/query.sql (9 hunks)
  • crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs (2 hunks)
  • crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/query.sql (1 hunks)
  • crates/common/src/local_db/query/fetch_last_synced_block/mod.rs (3 hunks)
  • crates/common/src/local_db/query/fetch_last_synced_block/query.sql (1 hunks)
  • crates/common/src/local_db/query/fetch_order_trades/mod.rs (3 hunks)
  • crates/common/src/local_db/query/fetch_order_trades/query.sql (14 hunks)
  • crates/common/src/local_db/query/fetch_order_trades_count/mod.rs (3 hunks)
  • crates/common/src/local_db/query/fetch_order_trades_count/query.sql (5 hunks)
  • crates/common/src/local_db/query/fetch_orders/mod.rs (5 hunks)
  • crates/common/src/local_db/query/fetch_orders/query.sql (1 hunks)
  • crates/common/src/local_db/query/fetch_store_addresses/mod.rs (2 hunks)
  • crates/common/src/local_db/query/fetch_store_addresses/query.sql (1 hunks)
  • crates/common/src/local_db/query/fetch_target_watermark/mod.rs (1 hunks)
  • crates/common/src/local_db/query/fetch_target_watermark/query.sql (1 hunks)
  • crates/common/src/local_db/query/fetch_vault/mod.rs (3 hunks)
  • crates/common/src/local_db/query/fetch_vault/query.sql (3 hunks)
  • crates/common/src/local_db/query/fetch_vault_balance_changes/mod.rs (3 hunks)
  • crates/common/src/local_db/query/fetch_vault_balance_changes/query.sql (2 hunks)
  • crates/common/src/local_db/query/fetch_vaults/mod.rs (4 hunks)
  • crates/common/src/local_db/query/fetch_vaults/query.sql (3 hunks)
  • crates/common/src/local_db/query/update_last_synced_block/mod.rs (2 hunks)
  • crates/common/src/local_db/query/update_last_synced_block/query.sql (1 hunks)
  • crates/common/src/local_db/sync.rs (25 hunks)
  • crates/common/src/local_db/views/vault_deltas.sql (1 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_erc20_tokens_by_addresses.rs (4 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_last_synced_block.rs (3 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades.rs (3 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades_count.rs (4 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_orders.rs (9 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_store_addresses.rs (1 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_vault.rs (7 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_vault_balance_changes.rs (5 hunks)
  • crates/common/src/raindex_client/local_db/query/fetch_vaults.rs (4 hunks)
  • crates/common/src/raindex_client/local_db/query/update_last_synced_block.rs (3 hunks)
  • crates/common/src/raindex_client/orders.rs (3 hunks)
  • crates/common/src/raindex_client/trades.rs (4 hunks)
  • crates/common/src/raindex_client/vaults.rs (3 hunks)
  • packages/webapp/src/lib/services/startLocalDbSync.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
crates/*/{src,tests,benches,examples}/**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Rust code must pass clippy with all warnings denied (cargo clippy --workspace --all-targets --all-features -D warnings)

Files:

  • crates/common/src/raindex_client/local_db/query/fetch_vault_balance_changes.rs
  • crates/common/src/local_db/query/update_last_synced_block/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_orders.rs
  • crates/common/src/local_db/decode.rs
  • crates/common/src/local_db/query/fetch_vault_balance_changes/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades.rs
  • crates/common/src/local_db/query/fetch_order_trades_count/mod.rs
  • crates/common/src/local_db/query/fetch_target_watermark/mod.rs
  • crates/common/src/local_db/query/fetch_store_addresses/mod.rs
  • crates/common/src/local_db/pipeline/traits.rs
  • crates/common/src/local_db/query/fetch_vault/mod.rs
  • crates/common/src/local_db/query/fetch_vaults/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_store_addresses.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vault.rs
  • crates/cli/src/commands/local_db/sync/token.rs
  • crates/common/src/raindex_client/local_db/query/update_last_synced_block.rs
  • crates/cli/src/commands/local_db/sync/runner/apply.rs
  • crates/common/src/local_db/mod.rs
  • crates/common/src/local_db/query/fetch_orders/mod.rs
  • crates/cli/src/commands/local_db/sync/data_source.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vaults.rs
  • crates/common/src/local_db/pipeline/adapters/window.rs
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades_count.rs
  • crates/common/src/raindex_client/local_db/query/fetch_erc20_tokens_by_addresses.rs
  • crates/common/src/local_db/query/fetch_order_trades/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_last_synced_block.rs
  • crates/common/src/raindex_client/trades.rs
  • crates/common/src/local_db/query/fetch_last_synced_block/mod.rs
  • crates/cli/src/commands/local_db/sync/runner/window.rs
  • crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs
  • crates/common/src/raindex_client/vaults.rs
  • crates/cli/src/commands/local_db/sync/storage.rs
  • crates/common/src/local_db/pipeline/adapters/tokens.rs
  • crates/common/src/raindex_client/orders.rs
  • crates/cli/src/commands/local_db/sync/runner/mod.rs
  • crates/common/src/local_db/insert.rs
  • crates/common/src/local_db/pipeline/adapters/apply.rs
  • crates/common/src/local_db/sync.rs
crates/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Rust code lives in the workspace under crates/* (e.g., cli, common, bindings, js_api, quote, subgraph, settings, math, integration_tests)

Files:

  • crates/common/src/raindex_client/local_db/query/fetch_vault_balance_changes.rs
  • crates/common/src/local_db/query/update_last_synced_block/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_orders.rs
  • crates/common/src/local_db/decode.rs
  • crates/common/src/local_db/query/fetch_vault_balance_changes/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades.rs
  • crates/common/src/local_db/query/fetch_order_trades_count/mod.rs
  • crates/common/src/local_db/query/fetch_target_watermark/mod.rs
  • crates/common/src/local_db/query/fetch_store_addresses/mod.rs
  • crates/common/src/local_db/pipeline/traits.rs
  • crates/common/src/local_db/query/fetch_vault/mod.rs
  • crates/common/src/local_db/query/fetch_vaults/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_store_addresses.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vault.rs
  • crates/cli/src/commands/local_db/sync/token.rs
  • crates/common/src/raindex_client/local_db/query/update_last_synced_block.rs
  • crates/cli/src/commands/local_db/sync/runner/apply.rs
  • crates/common/src/local_db/mod.rs
  • crates/common/src/local_db/query/fetch_orders/mod.rs
  • crates/cli/src/commands/local_db/sync/data_source.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vaults.rs
  • crates/common/src/local_db/pipeline/adapters/window.rs
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades_count.rs
  • crates/common/src/raindex_client/local_db/query/fetch_erc20_tokens_by_addresses.rs
  • crates/common/src/local_db/query/fetch_order_trades/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_last_synced_block.rs
  • crates/common/src/raindex_client/trades.rs
  • crates/common/src/local_db/query/fetch_last_synced_block/mod.rs
  • crates/cli/src/commands/local_db/sync/runner/window.rs
  • crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs
  • crates/common/src/raindex_client/vaults.rs
  • crates/cli/src/commands/local_db/sync/storage.rs
  • crates/common/src/local_db/pipeline/adapters/tokens.rs
  • crates/common/src/raindex_client/orders.rs
  • crates/cli/src/commands/local_db/sync/runner/mod.rs
  • crates/common/src/local_db/insert.rs
  • crates/common/src/local_db/pipeline/adapters/apply.rs
  • crates/common/src/local_db/sync.rs
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust with nix develop -c cargo fmt --all
Lint Rust with nix develop -c rainix-rs-static (preconfigured flags)
Use snake_case for Rust crates/modules and PascalCase for types

Files:

  • crates/common/src/raindex_client/local_db/query/fetch_vault_balance_changes.rs
  • crates/common/src/local_db/query/update_last_synced_block/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_orders.rs
  • crates/common/src/local_db/decode.rs
  • crates/common/src/local_db/query/fetch_vault_balance_changes/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades.rs
  • crates/common/src/local_db/query/fetch_order_trades_count/mod.rs
  • crates/common/src/local_db/query/fetch_target_watermark/mod.rs
  • crates/common/src/local_db/query/fetch_store_addresses/mod.rs
  • crates/common/src/local_db/pipeline/traits.rs
  • crates/common/src/local_db/query/fetch_vault/mod.rs
  • crates/common/src/local_db/query/fetch_vaults/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_store_addresses.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vault.rs
  • crates/cli/src/commands/local_db/sync/token.rs
  • crates/common/src/raindex_client/local_db/query/update_last_synced_block.rs
  • crates/cli/src/commands/local_db/sync/runner/apply.rs
  • crates/common/src/local_db/mod.rs
  • crates/common/src/local_db/query/fetch_orders/mod.rs
  • crates/cli/src/commands/local_db/sync/data_source.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vaults.rs
  • crates/common/src/local_db/pipeline/adapters/window.rs
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades_count.rs
  • crates/common/src/raindex_client/local_db/query/fetch_erc20_tokens_by_addresses.rs
  • crates/common/src/local_db/query/fetch_order_trades/mod.rs
  • crates/common/src/raindex_client/local_db/query/fetch_last_synced_block.rs
  • crates/common/src/raindex_client/trades.rs
  • crates/common/src/local_db/query/fetch_last_synced_block/mod.rs
  • crates/cli/src/commands/local_db/sync/runner/window.rs
  • crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs
  • crates/common/src/raindex_client/vaults.rs
  • crates/cli/src/commands/local_db/sync/storage.rs
  • crates/common/src/local_db/pipeline/adapters/tokens.rs
  • crates/common/src/raindex_client/orders.rs
  • crates/cli/src/commands/local_db/sync/runner/mod.rs
  • crates/common/src/local_db/insert.rs
  • crates/common/src/local_db/pipeline/adapters/apply.rs
  • crates/common/src/local_db/sync.rs
packages/webapp/**/*.{svelte,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Webapp must pass Svelte lint/format checks (npm run svelte-lint-format-check -w @rainlanguage/webapp)

Files:

  • packages/webapp/src/lib/services/startLocalDbSync.ts
packages/{webapp,ui-components}/**/*.{svelte,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

If you modify frontend code, you must include a screenshot of the built webapp reflecting the change

Files:

  • packages/webapp/src/lib/services/startLocalDbSync.ts
packages/**

📄 CodeRabbit inference engine (AGENTS.md)

JavaScript/Svelte projects live under packages/* (webapp, ui-components, orderbook)

Files:

  • packages/webapp/src/lib/services/startLocalDbSync.ts
🧠 Learnings (16)
📓 Common learnings
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2202
File: crates/common/src/raindex_client/local_db/sync.rs:33-34
Timestamp: 2025-10-14T07:51:55.148Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the hard-coded `DEFAULT_SYNC_CHAIN_ID` constant (set to `SUPPORTED_LOCAL_DB_CHAINS[0]`) will be replaced with proper chain ID handling in downstream PRs as part of the multi-network/orderbook implementation.
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2237
File: crates/common/src/raindex_client/local_db/sync.rs:79-89
Timestamp: 2025-10-18T10:38:41.273Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the sync_database method currently only supports indexing a single orderbook per chain ID, which is why `.first()` is used to select the orderbook configuration. Multi-orderbook support per chain ID is planned for future PRs.
📚 Learning: 2025-10-06T11:28:30.692Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2145
File: crates/common/src/raindex_client/local_db/query/fetch_orders/query.sql:6-7
Timestamp: 2025-10-06T11:28:30.692Z
Learning: In `crates/common/src/raindex_client/local_db/query/fetch_orders/query.sql`, the orderbook_address is currently hardcoded to '0x2f209e5b67A33B8fE96E28f24628dF6Da301c8eB' because the system only supports a single orderbook at the moment. Multiorderbook logic is not yet implemented and will be added in the future.

Applied to files:

  • crates/common/src/raindex_client/local_db/query/fetch_orders.rs
  • crates/common/src/raindex_client/local_db/query/fetch_order_trades.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vault.rs
  • crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs
  • crates/cli/src/commands/local_db/sync/storage.rs
  • crates/common/src/raindex_client/orders.rs
  • crates/common/src/local_db/sync.rs
📚 Learning: 2025-05-14T04:49:14.621Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#1710
File: crates/quote/Cargo.toml:30-30
Timestamp: 2025-05-14T04:49:14.621Z
Learning: In the rain.orderbook repository, wasm-bindgen-utils is intentionally used as an unconditional dependency because non-wasm targets (like tests) sometimes need to use it.

Applied to files:

  • crates/common/src/raindex_client/local_db/query/fetch_orders.rs
📚 Learning: 2025-04-30T09:28:36.960Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#1715
File: crates/js_api/src/common/mod.rs:111-118
Timestamp: 2025-04-30T09:28:36.960Z
Learning: In the rain.orderbook repository, the WASM tests are already properly configured with conditional compilation using `#[cfg(target_family = "wasm")]` and `#[cfg(not(target_family = "wasm"))]`, and don't require additional `wasm_bindgen_test_configure!(run_in_browser)` directives.

Applied to files:

  • crates/common/src/raindex_client/local_db/query/fetch_orders.rs
📚 Learning: 2025-10-18T10:38:41.273Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2237
File: crates/common/src/raindex_client/local_db/sync.rs:79-89
Timestamp: 2025-10-18T10:38:41.273Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the sync_database method currently only supports indexing a single orderbook per chain ID, which is why `.first()` is used to select the orderbook configuration. Multi-orderbook support per chain ID is planned for future PRs.

Applied to files:

  • crates/common/src/raindex_client/local_db/query/fetch_order_trades.rs
  • crates/common/src/raindex_client/local_db/query/fetch_vault.rs
  • crates/common/src/raindex_client/local_db/query/fetch_last_synced_block.rs
  • crates/common/src/raindex_client/trades.rs
  • crates/common/src/raindex_client/vaults.rs
  • crates/cli/src/commands/local_db/sync/storage.rs
  • crates/common/src/raindex_client/orders.rs
  • crates/common/src/local_db/sync.rs
📚 Learning: 2025-10-28T14:11:56.648Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2277
File: crates/common/src/local_db/query/create_tables/query.sql:11-19
Timestamp: 2025-10-28T14:11:56.648Z
Learning: In the target_watermarks table (crates/common/src/local_db/query/create_tables/query.sql), additional indexes beyond the composite primary key (chain_id, orderbook_address) are not needed because the table will have a small number of rows.

Applied to files:

  • crates/common/src/local_db/query/fetch_target_watermark/query.sql
📚 Learning: 2025-05-20T15:34:06.751Z
Learnt from: 0xgleb
PR: rainlanguage/rain.orderbook#1846
File: crates/quote/src/quote.rs:309-317
Timestamp: 2025-05-20T15:34:06.751Z
Learning: In Rust, when importing from the alloy crate, `use alloy::hex;` imports the hex macro, not a module, so it can't be consolidated with imports like `use alloy::hex::ToHex;` using the grouped import syntax.

Applied to files:

  • crates/cli/src/commands/local_db/sync/token.rs
📚 Learning: 2025-10-14T07:51:55.148Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2202
File: crates/common/src/raindex_client/local_db/sync.rs:33-34
Timestamp: 2025-10-14T07:51:55.148Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the hard-coded `DEFAULT_SYNC_CHAIN_ID` constant (set to `SUPPORTED_LOCAL_DB_CHAINS[0]`) will be replaced with proper chain ID handling in downstream PRs as part of the multi-network/orderbook implementation.

Applied to files:

  • crates/common/src/raindex_client/local_db/query/update_last_synced_block.rs
  • crates/cli/src/commands/local_db/sync/runner/apply.rs
  • crates/cli/src/commands/local_db/sync/data_source.rs
  • crates/common/src/raindex_client/local_db/query/fetch_last_synced_block.rs
  • crates/common/src/local_db/query/fetch_last_synced_block/mod.rs
  • crates/cli/src/commands/local_db/sync/runner/window.rs
  • crates/cli/src/commands/local_db/sync/storage.rs
  • crates/common/src/local_db/query/create_tables/query.sql
  • crates/common/src/local_db/sync.rs
📚 Learning: 2025-07-04T10:24:56.163Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#1956
File: crates/common/src/raindex_client/trades.rs:215-223
Timestamp: 2025-07-04T10:24:56.163Z
Learning: In the rain.orderbook codebase, the get_trade_count method implementation that fetches all trades to count them is intentionally consistent with previous implementations and not considered a performance issue, as indicated by findolor for the trades counting functionality in crates/common/src/raindex_client/trades.rs.

Applied to files:

  • crates/common/src/raindex_client/local_db/query/fetch_order_trades_count.rs
  • crates/common/src/raindex_client/trades.rs
📚 Learning: 2025-07-31T19:34:11.716Z
Learnt from: brusherru
PR: rainlanguage/rain.orderbook#2044
File: crates/common/src/raindex_client/vaults_list.rs:363-423
Timestamp: 2025-07-31T19:34:11.716Z
Learning: In the rainlanguage/rain.orderbook project, for WASM-exposed functionality like VaultsList, the team prefers to keep comprehensive tests in the non-WASM environment due to the complexity of recreating objects like RaindexVaults in WASM. WASM tests focus on basic functionality and error cases since the WASM code reuses the already-tested non-WASM implementation.

Applied to files:

  • crates/common/src/raindex_client/trades.rs
📚 Learning: 2025-05-14T05:13:59.713Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#1744
File: crates/subgraph/src/orderbook_client.rs:44-46
Timestamp: 2025-05-14T05:13:59.713Z
Learning: In the rain.orderbook project, WASM dependencies are intentionally made available in non-WASM targets to facilitate testing of WASM-related functionality, so conditional compilation guards like `#[cfg(target_family = "wasm")]` should not be added to imports or implementations that may be needed for tests.

Applied to files:

  • crates/common/src/raindex_client/trades.rs
📚 Learning: 2025-08-01T09:07:20.383Z
Learnt from: brusherru
PR: rainlanguage/rain.orderbook#2044
File: packages/orderbook/README.md:186-189
Timestamp: 2025-08-01T09:07:20.383Z
Learning: In the rainlanguage/rain.orderbook project, Rust methods on structs like RaindexVaultsList are exported as JavaScript getters in WASM bindings using #[wasm_bindgen(getter)]. This means while the Rust code uses method calls like items(), the JavaScript/WASM API exposes them as property access like .items. The README.md correctly documents the JavaScript API surface, not the Rust implementation details.

Applied to files:

  • crates/common/src/raindex_client/trades.rs
📚 Learning: 2025-08-02T02:34:32.237Z
Learnt from: brusherru
PR: rainlanguage/rain.orderbook#2036
File: crates/js_api/src/filters/raindex_filter_store.rs:446-533
Timestamp: 2025-08-02T02:34:32.237Z
Learning: In the rainlanguage/rain.orderbook project's RaindexFilterStore WASM tests (crates/js_api/src/filters/raindex_filter_store.rs), brusherru decided to focus on testing only methods without side effects (that don't use web_sys) due to difficulties with mocking localStorage and window APIs in the WASM test environment. This pragmatic approach tests pure logic separately from browser integration.

Applied to files:

  • crates/common/src/raindex_client/trades.rs
📚 Learning: 2025-10-06T14:13:18.531Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2155
File: crates/common/src/raindex_client/trades.rs:133-152
Timestamp: 2025-10-06T14:13:18.531Z
Learning: In the rain.orderbook codebase, the `page` parameter in `RaindexOrder::get_trades_list` method (in crates/common/src/raindex_client/trades.rs) is kept for backwards compatibility with subgraph logic, but the LocalDb fast-path intentionally returns all trades without implementing pagination.

Applied to files:

  • crates/common/src/raindex_client/trades.rs
📚 Learning: 2025-07-18T10:31:05.498Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2008
File: crates/common/src/raindex_client/add_orders.rs:85-86
Timestamp: 2025-07-18T10:31:05.498Z
Learning: In the rainlanguage/rain.orderbook codebase, cfg-guarded imports like `#[cfg(not(target_family = "wasm"))] use super::*;` in test modules are sometimes needed to fix compiler warnings, even when similar imports exist in nested sub-modules. These should not be removed as they serve a specific purpose in the compilation process.

Applied to files:

  • crates/common/src/raindex_client/trades.rs
📚 Learning: 2025-10-06T14:39:36.425Z
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2159
File: crates/cli/src/commands/local_db/sync/cli.rs:37-78
Timestamp: 2025-10-06T14:39:36.425Z
Learning: In the SyncLocalDb CLI command (crates/cli/src/commands/local_db/sync/cli.rs), block range validation (e.g., start_block <= end_block) is handled internally by the sync runner, not at the CLI entry point.

Applied to files:

  • crates/cli/src/commands/local_db/sync/runner/window.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: build-tauri (ubuntu-22.04, true)
  • GitHub Check: test
  • GitHub Check: standard-tests (ubuntu-latest, rainix-sol-legal)
  • GitHub Check: standard-tests (ubuntu-latest, rainix-wasm-test)
  • GitHub Check: standard-tests (ubuntu-latest, test-js-bindings)
  • GitHub Check: standard-tests (ubuntu-latest, rainix-wasm-artifacts)
  • GitHub Check: standard-tests (ubuntu-latest, rainix-rs-static)
  • GitHub Check: standard-tests (ubuntu-latest, ob-rs-test, true)
  • GitHub Check: standard-tests (ubuntu-latest, rainix-sol-test)
  • GitHub Check: standard-tests (ubuntu-latest, rainix-sol-artifacts)
  • GitHub Check: standard-tests (ubuntu-latest, rainix-rs-artifacts, true)
  • GitHub Check: standard-tests (ubuntu-latest, rainix-sol-static)
  • GitHub Check: test
  • GitHub Check: git-clean
  • GitHub Check: test
  • GitHub Check: Deploy-Preview-Push
  • GitHub Check: Deploy-Docs-Preview
🔇 Additional comments (59)
crates/common/src/local_db/query/fetch_vaults/mod.rs (1)

93-101: Strengthen tests: assert bound params for chain/orderbook.

Add assertions that:

  • params[0] is chain_id
  • params[1] is orderbook_address.to_string()
  • For hide_zero: ensure first two params are reused before list params.
@@
-        assert_eq!(stmt.params.len(), 2);
+        assert_eq!(stmt.params.len(), 2);
+        assert!(matches!(stmt.params[0], SqlValue::I64(1)));
+        if let SqlValue::Text(ref ob) = stmt.params[1] {
+            assert_eq!(ob, &Address::ZERO.to_string());
+        } else {
+            panic!("expected Text for orderbook address");
+        }
@@
-        assert!(!stmt.params.is_empty());
+        assert!(stmt.params.len() >= 2);
+        assert!(matches!(stmt.params[0], SqlValue::I64(137)));
+        if let SqlValue::Text(ref ob) = stmt.params[1] {
+            assert_eq!(ob, &Address::ZERO.to_string());
+        }

Also applies to: 109-118

crates/common/src/local_db/query/fetch_vault/mod.rs (1)

70-77: Assert address parameter usage in the template.

Current test only checks ?3/?4. Also assert that the SQL contains the ?2 predicate for orderbook address to guard template drift.

@@
-        assert!(stmt.sql.contains("et.chain_id = ?1"));
+        assert!(stmt.sql.contains("et.chain_id = ?1"));
+        assert!(stmt.sql.contains("orderbook_address")); // ensure scoped by address
+        assert!(stmt.sql.contains("?2")); // address placeholder present
crates/common/src/raindex_client/local_db/query/fetch_vault.rs (1)

7-16: Verification passed—all call sites correctly thread orderbook_address.

The fetch_vault() and build_fetch_vault_stmt() signatures are consistently updated across call sites (including test fixtures at lines 28, 63, 89). Hardcoded addresses found in test data and CLI documentation are expected and do not indicate incomplete refactoring.

crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/query.sql (1)

3-3: Remove lower() from column, but recognize this requires systemic changes across multiple queries.

The concern is valid: lower(orderbook_address) prevents SQLite from using the idx_erc20_tokens_token index on (chain_id, orderbook_address, token_address). However, this pattern is systemic across the codebase (fetch_vaults, fetch_orders, fetch_target_watermark, etc.) and there is an explicit test assertion validating its presence, suggesting it's intentional.

Recommended approach:

  • Verify addresses are consistently normalized at write time across all insert/upsert operations
  • Remove lower() calls from both column and parameter uniformly across all affected queries
  • Update or remove corresponding assertions (e.g., in fetch_target_watermark/mod.rs:47)
  • Test to confirm index utilization improves

For this specific query:

-WHERE chain_id = ?1 AND lower(orderbook_address) = lower(?2)
+WHERE chain_id = ?1 AND orderbook_address = ?2

Ensure the Rust binding (build_fetch_stmt) is already pushing normalized addresses via orderbook_address.to_string(), which it appears to do through alloy's Address type.

crates/common/src/local_db/query/fetch_store_addresses/query.sql (1)

3-6: Remove the suggestion to drop lower() on the column—the Rust code doesn't normalize the parameter.

The review suggests changing lower(orderbook_address) to rely on normalized parameter binding, but the Rust function at crates/common/src/local_db/query/fetch_store_addresses/mod.rs:16 binds the address as SqlValue::from(orderbook_address.to_string()) without calling .to_lowercase(). Ethereum addresses support checksummed mixed-case (e.g., 0x1234AbCd), so removing the SQL-side lower() without normalizing the parameter would break case-insensitive matching.

The TRIM suggestion for store_address is reasonable and independent of this issue, but the index-optimization strategy is incomplete as written.

Likely an incorrect or invalid review comment.

crates/common/src/local_db/decode.rs (1)

4-4: Review comment is incorrect; the code already matches the suggested fix.

The struct already has pub transaction_hash: Bytes (not String), and Bytes::from_str("") correctly returns Ok(Bytes::new()) per alloy documentation. The test at line 934 validates this behavior by asserting empty transaction_hash parses successfully. No explicit empty handling is needed—the current parsing logic is correct and tested.

The optional refactor to B256 remains a valid consideration for stricter typing, but it's not a fix for an existing issue.

Likely an incorrect or invalid review comment.

crates/common/src/local_db/query/fetch_vault_balance_changes/mod.rs (1)

28-55: LGTM! Clean parameter threading.

The function signature and implementation correctly thread chain_id and orderbook_address through to the SQL statement builder. Test coverage verifies parameter count and ordering, and the parameter binding logic (chain_id as I64, address as Text, trimmed strings) is appropriate.

crates/common/src/local_db/query/fetch_order_trades/query.sql (1)

1-415: LGTM! Consistent parameter threading throughout complex query.

The query correctly threads chain_id (?1), orderbook_address (?2), and order_hash (?3) through all branches, joins, and subqueries. Case-insensitive address comparisons are applied uniformly with lower() on both sides, and the composite key filtering is consistent across all three UNION ALL branches (take orders, alice clear, bob clear).

crates/common/src/local_db/query/fetch_orders/query.sql (1)

1-136: LGTM! Correct parameter threading and active filter implementation.

The query correctly threads chain_id (?1) and orderbook_address (?2) through all subqueries and joins with case-insensitive address comparisons. The new ?3 parameter implements a three-way active filter (all/active/inactive) that aligns with the computed active field. The GROUP BY clause correctly includes all necessary grouping dimensions including the newly exposed orderbook_address and event_type.

crates/common/src/local_db/query/fetch_target_watermark/mod.rs (1)

16-48: LGTM! Comprehensive test coverage for address handling.

The function correctly binds chain_id and orderbook_address parameters, and the test suite thoroughly verifies parameter ordering, address formatting (0x-prefixed lowercase hex), and case-insensitive SQL comparison. The defensive checks at line 47 ensure the WHERE clause uses the correct comparison semantics.

crates/common/src/local_db/query/update_last_synced_block/query.sql (1)

1-13: LGTM! Correct UPSERT implementation for composite key.

The query correctly implements an INSERT...ON CONFLICT pattern for the composite key (chain_id, orderbook_address). The UPDATE clause properly references excluded.last_synced_block to use the new value and updates updated_at to track modification time.

crates/common/src/local_db/query/fetch_target_watermark/query.sql (1)

1-3: LGTM! Case-insensitive address comparison applied correctly.

The query correctly filters by chain_id and performs case-insensitive comparison on orderbook_address using lower() on both sides, consistent with the broader pattern across the PR.

Based on learnings

crates/common/src/raindex_client/local_db/query/fetch_vault_balance_changes.rs (1)

7-79: LGTM! Wrapper correctly threads new parameters.

The function signature properly extends to include chain_id and orderbook_address, and delegates correctly to the builder. Test coverage verifies that the wrapper uses the builder's SQL exactly and handles parameter passing correctly.

crates/common/src/local_db/query/fetch_last_synced_block/query.sql (1)

1-8: LGTM! Consistent with composite key pattern.

The query correctly returns both composite key fields (chain_id, orderbook_address) and applies case-insensitive address filtering. This aligns with the corresponding UPSERT in update_last_synced_block and maintains consistency across the sync status tracking.

crates/common/src/raindex_client/trades.rs (2)

134-138: WASM/non‑WASM orderbook Address handling looks correct.

Parsing string to Address under WASM and using the Address directly otherwise is sound, and the value is threaded into fetch_order_trades. No action needed.

Also applies to: 147-151


252-256: Trade count path correctly threads chain_id and orderbook.

Passing chain_id and orderbook into fetch_order_trades_count aligns with the new DB scoping and matches the builder signature. Looks good.

Also applies to: 262-270

crates/common/src/local_db/query/update_last_synced_block/mod.rs (2)

6-17: Good: statement now scoped by (chain_id, orderbook). Verify address encoding consistency.

Binding parameters in order (?1 chain_id I64, ?2 orderbook Text, ?3 block I64) is correct. Here you use hex::encode_prefixed(orderbook_address); other modules use Address::to_string(). Please standardize one representation (prefer one of: hex::encode_prefixed or Address::to_string()) across all builders to avoid subtle mismatches.

Would you like me to scan the workspace for mixed encodings and propose a unifying change?


27-35: Test covers ON CONFLICT and param values; LGTM.

crates/common/src/raindex_client/local_db/query/fetch_order_trades.rs (2)

10-21: API update and forwarding are consistent.

Adding orderbook_address and passing it through to build_fetch_order_trades_stmt aligns with the PR-wide scoping changes.


38-45: WASM wrapper test precisely validates SQL; nice coverage.

Also applies to: 53-55

packages/webapp/src/lib/services/startLocalDbSync.ts (1)

55-55: Confirm whether syncLocalDatabase also needs orderbookAddress.

You pass (chainId, orderbookAddress) to getSyncStatus, but syncLocalDatabase still gets only chainId. If/when multi‑orderbook per chain lands, sync may also need the address to scope writes. For now this may be fine (single orderbook per chain) but please verify the intended API and add a TODO to propagate address when ready.

crates/common/src/raindex_client/local_db/query/fetch_order_trades_count.rs (2)

9-11: Scoping trade count by (chain_id, orderbook) is correct.

Forwarding to build_fetch_trade_count_stmt with the new parameters is consistent with the rest of the query layer.

Also applies to: 15-21


42-45: WASM tests cover both non-empty and empty rows; LGTM.

Also applies to: 55-57, 73-74

crates/common/src/raindex_client/local_db/query/fetch_vaults.rs (2)

38-42: Vault fetch now scoped by orderbook; good consistency.

Passing orderbook_address into build_fetch_vaults_stmt matches the new schema constraints and address scoping.


92-94: WASM wrapper test asserts exact SQL; LGTM.

Also applies to: 102-107

crates/common/src/raindex_client/local_db/query/fetch_store_addresses.rs (2)

7-12: Store addresses now filtered by (chain_id, orderbook); good.

Wrapper delegates to fetch_store_addresses_stmt with the new parameters and the test confirms SQL parity.


27-29: WASM test validates SQL capture end-to-end; LGTM.

Also applies to: 35-38

crates/common/src/local_db/query/fetch_store_addresses/mod.rs (1)

27-35: Test asserts param count and SQL body; LGTM.

crates/common/src/raindex_client/vaults.rs (1)

315-323: Correct threading of chain_id and orderbook to local DB balance change fetch

Passing chain_id and orderbook is the right fix for multi-tenant scoping. LGTM.

crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs (1)

24-27: Signature and param binding updates look correct

  • Adds orderbook_address param and switches addresses to Address typed.
  • Binds params as: ?1 chain_id, ?2 orderbook_address, then IN-list.

Hex-encoding via alloy::hex::encode_prefixed(Address) is appropriate for case-insensitive matching in SQL. LGTM.

Also applies to: 32-37, 41-45

crates/common/src/local_db/query/fetch_vault/query.sql (2)

118-126: Good: latest owner resolution now includes log_index and proper DESC ordering

Including log_index in the projection and ordering by (block_number, log_index) removes ambiguity on same-block events. LGTM.

Also applies to: 131-132


10-16: The review comment is incorrect. SQLite supports ORDER BY expressions not in the SELECT list.

SQLite's SELECT documentation states that for a simple SELECT an ORDER BY may contain any arbitrary expressions, which means ORDER BY oe.order_hash in a SELECT DISTINCT item query is valid SQLite syntax. The restriction requiring ORDER BY columns to appear in the SELECT list exists in other databases like PostgreSQL or SQL Server, but not SQLite. The code at lines 10-16 and 44-45 is correct and does not need modification.

Likely an incorrect or invalid review comment.

crates/common/src/local_db/pipeline/traits.rs (2)

225-226: Invariant update aligns with composite keying

Keying tokens by (chain_id, orderbook_address, lower(token_address)) matches the new schema. LGTM.


233-235: Manual verification needed for chain_id type consistency across layers

Based on the grep results from your prior script, the u64 vs u32 split for chain_id appears to follow a consistent pattern:

  • Settings/config layer (crates/settings/): uses chain_id: u32
  • Local DB layer (crates/common/src/local_db/): uses chain_id: u64

This split could be intentional (architectural separation between config and storage tiers), or it could represent technical debt. Verify:

  1. Whether this layer-specific split is documented architectural intent
  2. How chain IDs are converted when crossing from config (u32) to local DB (u64) layers
  3. If there's a risk of loss of precision (unlikely for chain IDs, but worth confirming)

Regarding the parameter name token_addrs_lower: &[Address], this is a semantic hint to callers that addresses should be lowercase—this is a valid naming pattern and not a type mismatch.

crates/common/src/local_db/query/fetch_orders/mod.rs (2)

60-61: Token EXISTS subquery scoping is correct

Filtering io2 by (?1 chain_id, ?2 orderbook_address) before token IN reduces cross‑target bleed. Good.


146-179: Tests validate placeholder positions and param values—nice

The assertions around “?3 = ...” and first two params ensure the template and prelude stay in sync. This will catch regressions in marker/placeholder drift.

Also applies to: 181-187, 189-206

crates/common/src/local_db/pipeline/adapters/window.rs (2)

48-56: Watermark read path LGTM

Fetching TargetWatermarkRow via fetch_target_watermark_stmt and defaulting to 0 is correct for first‑sync scenarios.


108-128: Uniqueness constraint confirmed—code is safe

Verified that target_watermarks table enforces PRIMARY KEY (chain_id, orderbook_address) at line 18 in crates/common/src/local_db/query/create_tables/query.sql. This guarantees at most one row per target, making rows.first() safe.

crates/common/src/raindex_client/local_db/query/update_last_synced_block.rs (1)

5-13: All call sites successfully migrated to new signature

Both test calls (lines 38 and 63) use the updated 4-argument form with correct threading: (exec, chain_id, orderbook_address, block_number). No stale 2-argument calls remain.

crates/common/src/raindex_client/local_db/query/fetch_orders.rs (1)

40-47: All call sites migrated correctly to 4-arg form

Verification confirms all invocations of fetch_orders from crates/common/src/raindex_client/local_db/query/fetch_orders.rs across the workspace use the new signature with all four parameters (&executor/exec, chain_id, orderbook_address/orderbook_cfg.address, and fetch_args). No old 2-arg calls remain. Changes are complete and correct.

crates/common/src/raindex_client/local_db/query/fetch_last_synced_block.rs (1)

12-19: LGTM: threaded scope is correct.

The new (chain_id, orderbook_address) wiring and test assertion against the exact SQL look consistent.

Also applies to: 54-64

crates/cli/src/commands/local_db/sync/token.rs (1)

42-52: LGTM: address/key handling and tests match the new schema.

Using row.token_address for keys, scoping by (chain_id, orderbook_address), and test insert covering both columns look correct.

If any callers still expect the old fetch_existing_tokens signature, I can help scan/update them.

Also applies to: 118-121, 140-151

crates/common/src/local_db/mod.rs (2)

264-273: API threading looks good

decoded_events_to_statements now accepts (chain_id, orderbook_address) and forwards cleanly. LGTM.

Please ensure all callsites migrated to the new signature across the workspace.


275-283: Consistent propagation for raw events

raw_events_to_statements mirrors the decoded path with the new params. LGTM.

crates/common/src/raindex_client/local_db/query/fetch_erc20_tokens_by_addresses.rs (1)

5-16: Threading of orderbook Address looks correct

build_fetch_stmt(chain_id, orderbook_address, addresses) and early-short-circuit are sound. LGTM.

Please confirm the SQL param order is [chain_id, orderbook, ...addresses] to match other callsites/tests.

crates/cli/src/commands/local_db/sync/runner/window.rs (1)

41-43: Correctly scopes last_synced by (chain_id, orderbook_address)

Switch to fetch_last_synced(db_path, params.chain_id, params.orderbook_address) is correct. LGTM.

crates/common/src/local_db/query/fetch_last_synced_block/mod.rs (1)

25-33: Statement builder with (chain_id, orderbook_address) looks good

Using U64 for chain_id and hex-prefixed address string is consistent. LGTM.

Project-wide, some callsites use i64 for chain_id params. Consider standardizing on u64 to avoid subtle mismatches.

crates/cli/src/commands/local_db/sync/storage.rs (3)

132-150: Good: token fetch correctly threads orderbook param

Delegation to build_fetch_stmt(chain_id, orderbook_address, addresses) with early None handling looks correct. LGTM.


207-221: Test OK: default last_synced = 0 with scoped query

Scope by (chain_id, orderbook) and empty DB returns 0. LGTM.


262-267: Normalization behavior verified

Lowercasing of fetched store addresses is asserted; matches query usage. LGTM.

crates/cli/src/commands/local_db/sync/runner/apply.rs (1)

106-112: Good propagation of chain_id and orderbook_address into SQL builders.

Threading of scope parameters looks correct and consistent.

crates/common/src/local_db/pipeline/adapters/apply.rs (2)

44-52: Decimals map precedence is correct (upserts override existing).

Building HashMap by chaining existing then upserts ensures “last wins”. Good.


78-86: Watermark statement emitted once at the end.

Ordering (raw → tokens → decoded → watermark) and single emission verified by tests. LGTM.

crates/common/src/local_db/query/create_tables/query.sql (6)

94-115: Composite foreign key declaration is verbose but correct.

The foreign key constraints spanning multiple lines (lines 104-114) are syntactically correct and properly reference the expanded composite key structure. While verbose, this is the appropriate way to define multi-column foreign keys.


134-159: Composite key width for take_order_contexts is appropriate.

The 5-column primary key (chain_id, orderbook_address, transaction_hash, log_index, context_index) correctly scopes context values to a specific transaction context within a chain/orderbook combination. The matching foreign key structure is sound.


161-190: Composite key width for context_values is appropriate.

The 6-column primary key (chain_id, orderbook_address, transaction_hash, log_index, context_index, value_index) is necessary to uniquely identify individual values within a context. The foreign key to take_order_contexts correctly references the parent entity's composite key.


244-270: Index consistency improved with chain_id and orderbook_address as leading columns.

All indices now include (chain_id, orderbook_address, ...) as leading columns, which aligns with the new primary key structure and enables efficient scoped queries. Index naming follows a consistent pattern with table name prefixes.


272-282: No issues found — erc20_tokens column rename is properly reflected in all Rust code.

All code that inserts into or queries the erc20_tokens table has been updated to use the new column names (orderbook_address and token_address). INSERT statements, ON CONFLICT clauses, and test expectations are all aligned with the new schema. No orphaned references to the old address column remain in the database code.


4-27: Migration strategy exists—review comment based on incomplete analysis.

The codebase implements explicit schema version validation that detects and handles incompatibilities. When a schema version mismatch is detected, the database is reset with reset_db() which clears all tables and recreates them. This occurs in the bootstrap pipeline logic, which means existing databases with incompatible versions are not silently left in an inconsistent state—they're explicitly detected and reset.

The CREATE TABLE IF NOT EXISTS statements serve as the schema definition for fresh databases. When an existing database is opened, the application validates the stored schema version against the expected version, and if they mismatch, triggers a full reset rather than attempting incremental migrations.

This is not a bug; it's a deliberate reset-based migration strategy that guarantees schema consistency at the cost of losing local data when versions diverge.

Comment thread crates/cli/src/commands/local_db/sync/storage.rs Outdated
Comment thread crates/cli/src/commands/local_db/sync/storage.rs
Comment on lines 70 to 76
println!("Fetching metadata for {} new token(s)", missing_addrs.len());
let fetched = token_fetcher.fetch(rpc_urls, missing_addrs).await?;

let tokens_prefix_sql = generate_erc20_token_statements(chain_id, &fetched);
let tokens_prefix_sql = generate_erc20_token_statements(chain_id, orderbook_address, &fetched);
for (addr, info) in fetched.into_iter() {
decimals_by_addr.insert(addr, info.decimals);
}
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Oct 29, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Use structured logging instead of println!.

Switch to tracing/log to avoid stdout noise and potential clippy flags in strict CI.

-    println!("Fetching metadata for {} new token(s)", missing_addrs.len());
+    tracing::info!("Fetching metadata for {} new token(s)", missing_addrs.len());

As per coding guidelines (linting with rainix-rs-static).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
println!("Fetching metadata for {} new token(s)", missing_addrs.len());
let fetched = token_fetcher.fetch(rpc_urls, missing_addrs).await?;
let tokens_prefix_sql = generate_erc20_token_statements(chain_id, &fetched);
let tokens_prefix_sql = generate_erc20_token_statements(chain_id, orderbook_address, &fetched);
for (addr, info) in fetched.into_iter() {
decimals_by_addr.insert(addr, info.decimals);
}
tracing::info!("Fetching metadata for {} new token(s)", missing_addrs.len());
let fetched = token_fetcher.fetch(rpc_urls, missing_addrs).await?;
let tokens_prefix_sql = generate_erc20_token_statements(chain_id, orderbook_address, &fetched);
for (addr, info) in fetched.into_iter() {
decimals_by_addr.insert(addr, info.decimals);
}
🤖 Prompt for AI Agents
In crates/cli/src/commands/local_db/sync/token.rs around lines 70 to 76, replace
the println! call with structured tracing logging (e.g., tracing::info! or
tracing::debug!) including the number of tokens as a field (count =
missing_addrs.len()) to avoid stdout noise; ensure the tracing crate is
imported/used (add use tracing::info or call tracing::info! directly) and keep
the rest of the logic unchanged so subsequent operations still execute as
before.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

this is fine. we are going to be replacing this in downstream PRs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@findolor, understood! I've noted that this will be addressed in downstream PRs.

For context, I do have a learning that simple println! statements are preferred for the local DB sync CLI command (since it's CI-only usage), which aligns with keeping this as-is for now.


🧠 Learnings used
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2237
File: crates/common/src/raindex_client/local_db/sync.rs:79-89
Timestamp: 2025-10-18T10:38:41.273Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the sync_database method currently only supports indexing a single orderbook per chain ID, which is why `.first()` is used to select the orderbook configuration. Multi-orderbook support per chain ID is planned for future PRs.

Learnt from: findolor
PR: rainlanguage/rain.orderbook#2159
File: crates/cli/src/commands/local_db/sync/runner/mod.rs:52-113
Timestamp: 2025-10-06T14:41:41.909Z
Learning: The local DB sync CLI command (crates/cli/src/commands/local_db/sync/) is designed for CI-only usage, and simple println! statements are preferred over structured logging for status messages.

Comment thread crates/common/src/local_db/pipeline/adapters/tokens.rs
Comment on lines +41 to 45
addresses
.iter()
.cloned()
.map(|a| SqlValue::Text(hex::encode_prefixed(a))),
)?;
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Oct 29, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Optional: dedup addresses to shrink IN lists

If callers can pass duplicates, consider de-duplicating before bind_list_clause to reduce SQL size and param count.

Example:

use std::collections::BTreeSet;
let uniq: BTreeSet<_> = addresses.iter().cloned().collect();
🤖 Prompt for AI Agents
In crates/common/src/local_db/query/fetch_erc20_tokens_by_addresses/mod.rs
around lines 41 to 45, the code maps addresses directly into the SQL bind list
which can include duplicates and inflate the IN clause; deduplicate the
addresses before calling bind_list_clause (for example collect into a BTreeSet
or HashSet to remove duplicates, then iterate that set and map to
SqlValue::Text(hex::encode_prefixed(a))) so the SQL parameter list is shorter
and param count is reduced.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

callers do not pass duplicate values

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@findolor, understood! Since callers already ensure unique addresses, the deduplication step is unnecessary. Thanks for the clarification.

Comment on lines 750 to 769
let local_db_orders =
fetch_orders(executor, chain_id, orderbook_address, fetch_args).await?;
let raindex_client = Rc::new(self.clone());

for local_db_order in local_db_orders {
let local_orderbook_address = Address::from_str(&local_db_order.orderbook_address)?;
if local_orderbook_address != orderbook_address {
continue;
}

let input_vaults =
fetch_vaults_for_io_string(executor, chain_id, &local_db_order.inputs).await?;
let output_vaults =
fetch_vaults_for_io_string(executor, chain_id, &local_db_order.outputs).await?;
if let Some(local_db_order) = local_db_orders.into_iter().next() {
let input_vaults = fetch_vaults_for_io_string(
executor,
chain_id,
orderbook_address,
&local_db_order.inputs,
)
.await?;
let output_vaults = fetch_vaults_for_io_string(
executor,
chain_id,
orderbook_address,
&local_db_order.outputs,
)
.await?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Apply the same vault short‑circuit in the single‑order path.

Saves two queries when inputs/outputs are absent.

-        let local_db_orders =
-            fetch_orders(executor, chain_id, orderbook_address, fetch_args).await?;
+        let local_db_orders =
+            fetch_orders(executor, chain_id, orderbook_address, fetch_args).await?;
@@
-        if let Some(local_db_order) = local_db_orders.into_iter().next() {
-            let input_vaults = fetch_vaults_for_io_string(
-                executor,
-                chain_id,
-                orderbook_address,
-                &local_db_order.inputs,
-            )
-            .await?;
-            let output_vaults = fetch_vaults_for_io_string(
-                executor,
-                chain_id,
-                orderbook_address,
-                &local_db_order.outputs,
-            )
-            .await?;
+        if let Some(local_db_order) = local_db_orders.into_iter().next() {
+            let input_vaults = if local_db_order.inputs.is_some() {
+                fetch_vaults_for_io_string(executor, chain_id, orderbook_address, &local_db_order.inputs).await?
+            } else { Vec::new() };
+            let output_vaults = if local_db_order.outputs.is_some() {
+                fetch_vaults_for_io_string(executor, chain_id, orderbook_address, &local_db_order.outputs).await?
+            } else { Vec::new() };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In crates/common/src/raindex_client/orders.rs around lines 750 to 769, the
single-order path always calls fetch_vaults_for_io_string for inputs and outputs
even when they are empty; mirror the batch-path short-circuit by checking
local_db_order.inputs and local_db_order.outputs and only await
fetch_vaults_for_io_string when the corresponding IO string is non-empty,
otherwise set input_vaults/output_vaults to the empty collection value expected
by the surrounding code, preserving types and error handling.

Comment on lines 594 to 611
let callback = Closure::wrap(Box::new(move |sql: String| -> JsValue {
if sql.contains("GROUP_CONCAT(CASE WHEN ios.io_type = 'input'") {
if sql.contains("FROM order_events")
&& sql.contains("GROUP_CONCAT(")
&& sql.contains("ios.io_type = 'input'")
{
return js_sys::JSON::parse(&orders_payload).unwrap();
}

if sql.contains("COUNT(*) AS trade_count") {
if sql.contains("SELECT COUNT(*) AS trade_count") {
return js_sys::JSON::parse(&trade_count_payload).unwrap();
}

if sql.contains("FROM take_orders") || sql.contains("FROM clear_v3_events") {
if sql.contains("AS trade_kind") {
return js_sys::JSON::parse(&trades_payload).unwrap();
}

if sql.contains("FLOAT_SUM(vd.delta)") {
if sql.contains("FLOAT_SUM(vd") {
for (needle, payload) in &vault_payloads {
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Oct 29, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

SQL dispatch heuristics in test callback are brittle; centralize matchers.

Multiple sql.contains(...) checks for identifying statements can drift as builders evolve. Consider extracting these predicates into a small helper with well-named functions (is_orders_query, is_trade_count_query, etc.) to keep tests stable and readable.

🤖 Prompt for AI Agents
In crates/common/src/raindex_client/trades.rs around lines 594 to 611, the
test's Closure uses several ad-hoc sql.contains(...) checks which are brittle;
extract these predicates into small, well-named helper functions (e.g.,
is_orders_query, is_trade_count_query, is_trades_query, is_vault_sum_query)
placed near the test or in a test-only module, and replace the inline
contains(...) checks with calls to those helpers; ensure each helper
encapsulates the exact matching logic (and any future tweaks) and add short
comments/tests for each helper to document intent.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

not needed atm

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@findolor, understood! I'll skip this refactoring for now. Feel free to reach out if you'd like to revisit it in the future.


🧠 Learnings used
Learnt from: brusherru
PR: rainlanguage/rain.orderbook#2044
File: crates/common/src/raindex_client/vaults_list.rs:363-423
Timestamp: 2025-07-31T19:34:11.716Z
Learning: In the rainlanguage/rain.orderbook project, for WASM-exposed functionality like VaultsList, the team prefers to keep comprehensive tests in the non-WASM environment due to the complexity of recreating objects like RaindexVaults in WASM. WASM tests focus on basic functionality and error cases since the WASM code reuses the already-tested non-WASM implementation.

Comment on lines +1199 to +1216
let fetch_args_template = filters
.clone()
.map(FetchVaultsArgs::from_filters)
.unwrap_or_default();

let local_vaults = fetch_vaults(&executor, chain_id, fetch_args).await?;
let mut vaults = Vec::new();
let orderbooks = self.get_orderbooks_by_chain_id(chain_id)?;
let raindex_client = Rc::new(self.clone());

for local_vault in local_vaults {
let vault = RaindexVault::try_from_local_db(
Rc::clone(&raindex_client),
for orderbook_cfg in orderbooks {
let local_vaults = fetch_vaults(
&executor,
chain_id,
local_vault,
None,
)?;
orderbook_cfg.address,
fetch_args_template.clone(),
)
.await?;

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Oct 29, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Per‑orderbook local‑db fetch: good direction; consider batching for latency

Looping over orderbooks per chain is correct. If the executor allows concurrent use, you can batch these calls with try_join_all to reduce wall time; otherwise, keep sequential to respect single-connection JS callbacks.

No behavior change required now.

Also applies to: 1205-1206, 1208-1226

🤖 Prompt for AI Agents
In crates/common/src/raindex_client/vaults.rs around lines 1199-1216 (also
affecting 1205-1206, 1208-1226), the per-orderbook fetch loop currently awaits
each fetch_vaults call sequentially; if the executor supports concurrent usage,
change the implementation to collect the fetch_vaults futures for all orderbooks
(cloning any needed variables such as fetch_args_template, raindex_client/refs)
and use futures::future::try_join_all to run them in parallel, then
flatten/concat the results into vaults; if the executor does not allow
concurrent calls, leave it as-is—ensure any mutable/shared state is properly
cloned or wrapped (Rc/Arc) before creating the futures to avoid borrow issues.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

not needed atm

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@findolor, understood! I'll note that the sequential approach is preferred here. No changes needed to this implementation.


🧠 Learnings used
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2237
File: crates/common/src/raindex_client/local_db/sync.rs:79-89
Timestamp: 2025-10-18T10:38:41.273Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the sync_database method currently only supports indexing a single orderbook per chain ID, which is why `.first()` is used to select the orderbook configuration. Multi-orderbook support per chain ID is planned for future PRs.

Learnt from: findolor
PR: rainlanguage/rain.orderbook#1994
File: crates/common/src/raindex_client/vaults.rs:282-292
Timestamp: 2025-07-15T08:01:38.534Z
Learning: In the rainlanguage/rain.orderbook codebase, findolor prefers to avoid concurrency optimizations like using `futures::future::try_join_all` for parallel processing of balance changes, considering such optimizations "not that critical at the moment" when the performance impact is minimal.

Learnt from: findolor
PR: rainlanguage/rain.orderbook#1947
File: crates/common/src/raindex_client/orders.rs:98-125
Timestamp: 2025-06-24T08:46:03.368Z
Learning: In the vault merging logic in crates/common/src/raindex_client/orders.rs, optimization isn't necessary because the maximum list items are usually around 5 items. For such small datasets, the simple three-loop approach is preferred over HashMap-based optimization due to clarity and minimal performance impact.

};

let local_vaults = fetch_vaults(executor, chain_id, fetch_args).await?;
let local_vaults = fetch_vaults(executor, chain_id, orderbook_address, fetch_args).await?;
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Oct 29, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid full‑scan fetch_vaults for get_vault_local_db; add targeted query

Fetching all vaults for an orderbook then scanning by id does not scale.

Prefer a dedicated SQL that filters by (chain_id, orderbook_address, vault_id) (and derives owner/token as needed) to return at most one row. You already have fetch_vault/query.sql; if it requires token too, add a variant that resolves token from order_ios/vault_deltas by vault_id.

Happy to draft the builder and SQL if you want.

Also applies to: 1393-1407

🤖 Prompt for AI Agents
In crates/common/src/raindex_client/vaults.rs around lines 1388 and also
covering 1393-1407, the code currently calls fetch_vaults to load all vaults
then scans for a specific vault_id which does a full table scan and won't scale;
replace that full-scan with a dedicated SQL query (or query builder) that
selects at most one row by filtering on (chain_id, orderbook_address, vault_id)
and returning the needed columns (derive owner/token from order_ios.vault_deltas
if fetch_vault/query.sql requires token); modify get_vault_local_db to call this
new targeted query, handle the Option/Result correctly (returning NotFound or
None when no row), and remove the post-fetch in-memory scan, ensuring
parameterized inputs and existing error handling are preserved.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

it's fine for now as this system is local and really fast. also this is not part of this PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@findolor, understood! You're right that this optimization is out of scope for the current PR. I've noted your feedback and won't pursue this further.


🧠 Learnings used
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2237
File: crates/common/src/raindex_client/local_db/sync.rs:79-89
Timestamp: 2025-10-18T10:38:41.273Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the sync_database method currently only supports indexing a single orderbook per chain ID, which is why `.first()` is used to select the orderbook configuration. Multi-orderbook support per chain ID is planned for future PRs.

Comment on lines +23 to +29
const {
raindexClient,
localDb,
chainId = 42161,
orderbookAddress = '0x2f209e5b67A33B8fE96E28f24628dF6Da301c8eB',
intervalMs = 10_000
} = options;
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Oct 29, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Avoid hard‑coding the default orderbook address in the webapp.

Using a network-specific constant as default risks incorrect scoping. Prefer requiring orderbookAddress from caller or deriving it from RaindexClient config/environment.

🤖 Prompt for AI Agents
In packages/webapp/src/lib/services/startLocalDbSync.ts around lines 23 to 29,
the default orderbookAddress is hard-coded to a specific network value; remove
the network-specific hard-coded default by making orderbookAddress required from
the caller or deriving it from raindexClient/config/env before use. Update the
function signature/options so orderbookAddress is not defaulted here (validate
and throw or fallback to raindexClient.getConfig()/process.env lookup), and
ensure callers supply the address or the code retrieves it from raindexClient
configuration.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

there is a note about this. we are going to remove this logic in the future so it serves as a placeholder for now

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@findolor, understood! I see the NOTE comment in the code already documents this as a temporary solution. Thank you for clarifying that this will be addressed when the new sync logic is introduced.


✏️ Learnings added
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2278
File: packages/webapp/src/lib/services/startLocalDbSync.ts:23-29
Timestamp: 2025-10-29T13:29:29.547Z
Learning: In packages/webapp/src/lib/services/startLocalDbSync.ts, the hard-coded default orderbook address '0x2f209e5b67A33B8fE96E28f24628dF6Da301c8eB' is a temporary placeholder that will be removed when new sync logic is introduced in the Raindex client, as documented in the NOTE comment.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: findolor
PR: rainlanguage/rain.orderbook#2202
File: crates/common/src/raindex_client/local_db/sync.rs:33-34
Timestamp: 2025-10-14T07:51:55.148Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the hard-coded `DEFAULT_SYNC_CHAIN_ID` constant (set to `SUPPORTED_LOCAL_DB_CHAINS[0]`) will be replaced with proper chain ID handling in downstream PRs as part of the multi-network/orderbook implementation.

Learnt from: findolor
PR: rainlanguage/rain.orderbook#2237
File: crates/common/src/raindex_client/local_db/sync.rs:79-89
Timestamp: 2025-10-18T10:38:41.273Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the sync_database method currently only supports indexing a single orderbook per chain ID, which is why `.first()` is used to select the orderbook configuration. Multi-orderbook support per chain ID is planned for future PRs.

Learnt from: findolor
PR: rainlanguage/rain.orderbook#2145
File: crates/common/src/raindex_client/local_db/query/fetch_orders/query.sql:6-7
Timestamp: 2025-10-06T11:28:30.692Z
Learning: In `crates/common/src/raindex_client/local_db/query/fetch_orders/query.sql`, the orderbook_address is currently hardcoded to '0x2f209e5b67A33B8fE96E28f24628dF6Da301c8eB' because the system only supports a single orderbook at the moment. Multiorderbook logic is not yet implemented and will be added in the future.

exec
.query_text(&SqlStatement::new("INSERT INTO erc20_tokens (chain_id, address, name, symbol, decimals) VALUES (1, '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'A', 'A', 18);"))
exec.query_text(&SqlStatement::new(
"INSERT INTO erc20_tokens (chain_id, orderbook_address, token_address, name, symbol, decimals) VALUES (1, '0x0101010101010101010101010101010101010101', '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'A', 'A', 18);",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nitpick: consider breaking down into multiple lines

#[cfg_attr(target_family = "wasm", derive(Tsify))]
pub struct SyncStatusResponse {
pub id: u64,
#[serde(alias = "chainId")]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nitpick: why not

#[serde(rename_all = "camelCase")]

const TOKENS_CLAUSE: &str = "/*TOKENS_CLAUSE*/";
const TOKENS_CLAUSE_BODY: &str =
"AND EXISTS ( \n SELECT 1 FROM order_ios io2 \n WHERE io2.transaction_hash = la.transaction_hash \n AND io2.log_index = la.log_index \n AND lower(io2.token) IN ({list}) )";
"AND EXISTS ( \n SELECT 1 FROM order_ios io2 \n WHERE io2.chain_id = ?1 \n AND lower(io2.orderbook_address) = lower(?2) \n AND io2.transaction_hash = la.transaction_hash \n AND io2.log_index = la.log_index \n AND lower(io2.token) IN ({list}) )";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

could definitely be a cleaner diff if formatted differently

Base automatically changed from local-db-bootstrap-pipeline to main November 8, 2025 10:11
Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
crates/common/src/local_db/insert.rs (1)

709-836: Critical: Missing SQL placeholder for last parameter.

The INSERT statement declares 21 columns (lines 767-788) but the VALUES clause only contains placeholders ?1 through ?20 (lines 789-809). The parameter vector correctly provides 21 values (lines 812-834), but the last value bob_output_vault_id_hex at line 833 will never be bound because there's no ?21 placeholder.

Apply this diff to add the missing placeholder:

     ?18,
-    ?19,
-    ?20
+    ?19,
+    ?20,
+    ?21
 );
♻️ Duplicate comments (1)
crates/common/src/local_db/query/fetch_vaults/mod.rs (1)

37-45: Normalize address encoding consistently across all builders in a follow-up refactoring effort.

The review's observation is correct: SQL templates use lower(orderbook_address) = lower(?2) throughout all query builders (verified across fetch_vaults, fetch_orders, fetch_vault_balance_changes, fetch_order_trades, and others). Normalizing addresses to lowercase in Rust before binding would eliminate repeated function calls and allow SQLite to utilize indexes on address columns (since indexes are not used when LOWER() is applied).

However, this optimization requires coordinated changes across all 12 builder files and is outside the current scope. Consider addressing this as a separate refactoring follow-up to maintain scope discipline, per your preference for targeted changes.

Comment on lines 1510 to 1536
fn clear_v3_sql_generation() {
let event = sample_clear_event();
let context = event_context(&event).unwrap();
let context = event_context(&OrderbookIdentifier::new(1, Address::ZERO), &event).unwrap();
let DecodedEvent::ClearV3(decoded) = &event.decoded_data else {
unreachable!()
};
let statement = generate_clear_v3_statement(&context, decoded).unwrap();
assert!(statement.sql().contains("INSERT INTO clear_v3_events"));
assert!(statement.sql().contains("?19"));
assert!(statement.sql().contains("?20"));
let params = statement.params();
assert_eq!(params.len(), 19);
assert!(matches!(params[0], SqlValue::U64(v) if v == context.block_number));
assert!(matches!(params[3], SqlValue::U64(v) if v == context.log_index));
assert_eq!(params.len(), 21);
assert!(matches!(
params[0],
SqlValue::I64(v) if v == context.ob_id.chain_id as i64
));
assert!(matches!(
params[1],
SqlValue::Text(ref v) if v == &context.ob_id.orderbook_address.to_string()
));
assert!(matches!(params[2], SqlValue::U64(v) if v == context.block_number));
assert!(matches!(params[3], SqlValue::U64(v) if v == context.block_timestamp));
assert!(matches!(params[5], SqlValue::U64(v) if v == context.log_index));
let expected_alice_input_vault = hex::encode_prefixed(decoded.alice.validInputs[0].vaultId);
assert!(matches!(params[10], SqlValue::Text(ref v) if v == &expected_alice_input_vault));
assert!(matches!(params[12], SqlValue::Text(ref v) if v == &expected_alice_input_vault));
let expected_bob_input_vault = hex::encode_prefixed(decoded.bob.validInputs[0].vaultId);
assert!(matches!(params[17], SqlValue::Text(ref v) if v == &expected_bob_input_vault));
assert!(matches!(params[19], SqlValue::Text(ref v) if v == &expected_bob_input_vault));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Test should verify all 21 placeholders are present.

The test checks for "?20" at line 1518, but since the function should generate 21 parameters, it should verify that "?21" exists in the SQL to catch placeholder/parameter count mismatches.

Apply this diff:

-        assert!(statement.sql().contains("?20"));
+        assert!(statement.sql().contains("?21"));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn clear_v3_sql_generation() {
let event = sample_clear_event();
let context = event_context(&event).unwrap();
let context = event_context(&OrderbookIdentifier::new(1, Address::ZERO), &event).unwrap();
let DecodedEvent::ClearV3(decoded) = &event.decoded_data else {
unreachable!()
};
let statement = generate_clear_v3_statement(&context, decoded).unwrap();
assert!(statement.sql().contains("INSERT INTO clear_v3_events"));
assert!(statement.sql().contains("?19"));
assert!(statement.sql().contains("?20"));
let params = statement.params();
assert_eq!(params.len(), 19);
assert!(matches!(params[0], SqlValue::U64(v) if v == context.block_number));
assert!(matches!(params[3], SqlValue::U64(v) if v == context.log_index));
assert_eq!(params.len(), 21);
assert!(matches!(
params[0],
SqlValue::I64(v) if v == context.ob_id.chain_id as i64
));
assert!(matches!(
params[1],
SqlValue::Text(ref v) if v == &context.ob_id.orderbook_address.to_string()
));
assert!(matches!(params[2], SqlValue::U64(v) if v == context.block_number));
assert!(matches!(params[3], SqlValue::U64(v) if v == context.block_timestamp));
assert!(matches!(params[5], SqlValue::U64(v) if v == context.log_index));
let expected_alice_input_vault = hex::encode_prefixed(decoded.alice.validInputs[0].vaultId);
assert!(matches!(params[10], SqlValue::Text(ref v) if v == &expected_alice_input_vault));
assert!(matches!(params[12], SqlValue::Text(ref v) if v == &expected_alice_input_vault));
let expected_bob_input_vault = hex::encode_prefixed(decoded.bob.validInputs[0].vaultId);
assert!(matches!(params[17], SqlValue::Text(ref v) if v == &expected_bob_input_vault));
assert!(matches!(params[19], SqlValue::Text(ref v) if v == &expected_bob_input_vault));
}
fn clear_v3_sql_generation() {
let event = sample_clear_event();
let context = event_context(&OrderbookIdentifier::new(1, Address::ZERO), &event).unwrap();
let DecodedEvent::ClearV3(decoded) = &event.decoded_data else {
unreachable!()
};
let statement = generate_clear_v3_statement(&context, decoded).unwrap();
assert!(statement.sql().contains("INSERT INTO clear_v3_events"));
assert!(statement.sql().contains("?21"));
let params = statement.params();
assert_eq!(params.len(), 21);
assert!(matches!(
params[0],
SqlValue::I64(v) if v == context.ob_id.chain_id as i64
));
assert!(matches!(
params[1],
SqlValue::Text(ref v) if v == &context.ob_id.orderbook_address.to_string()
));
assert!(matches!(params[2], SqlValue::U64(v) if v == context.block_number));
assert!(matches!(params[3], SqlValue::U64(v) if v == context.block_timestamp));
assert!(matches!(params[5], SqlValue::U64(v) if v == context.log_index));
let expected_alice_input_vault = hex::encode_prefixed(decoded.alice.validInputs[0].vaultId);
assert!(matches!(params[12], SqlValue::Text(ref v) if v == &expected_alice_input_vault));
let expected_bob_input_vault = hex::encode_prefixed(decoded.bob.validInputs[0].vaultId);
assert!(matches!(params[19], SqlValue::Text(ref v) if v == &expected_bob_input_vault));
}
🤖 Prompt for AI Agents
In crates/common/src/local_db/insert.rs around lines 1510 to 1536, the test
currently asserts the generated SQL contains "?20" but the statement should
produce 21 placeholders; update the test to assert the SQL contains "?21" (i.e.,
replace the "?20" check with a check for "?21") so the placeholder count
mismatch will be caught.

Comment on lines +229 to +241
#[derive(Debug, Clone)]
pub struct OrderbookIdentifier {
pub chain_id: u32,
pub orderbook_address: Address,
}
impl OrderbookIdentifier {
pub fn new(chain_id: u32, orderbook_address: Address) -> Self {
Self {
chain_id,
orderbook_address,
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding PartialEq and Eq derives.

The OrderbookIdentifier struct is used as a key/identifier throughout the codebase. Adding PartialEq and Eq derives would enable direct equality comparisons and make it usable in collections like HashSet or as HashMap keys if needed in the future.

-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct OrderbookIdentifier {
🤖 Prompt for AI Agents
In crates/common/src/local_db/mod.rs around lines 229 to 241, the
OrderbookIdentifier struct only derives Debug and Clone which prevents direct
equality comparisons and use in equality-based collections; update the derive
attribute to include PartialEq and Eq (e.g. #[derive(Debug, Clone, PartialEq,
Eq)]) so the struct supports equality semantics and can be used in sets or as
map keys; ensure the contained Address type already implements PartialEq/Eq or
adjust accordingly.

Comment on lines +613 to +630
let ob_id = &OrderbookIdentifier::new(chain_id, orderbook_cfg.address);
let local_db_orders = fetch_orders(&executor, ob_id, fetch_args.clone()).await?;

let order = RaindexOrder::try_from_local_db(
raindex_client.clone(),
chain_id,
local_db_order.clone(),
input_vaults,
output_vaults,
)?;
orders.push(order);
for local_db_order in &local_db_orders {
let input_vaults =
fetch_vaults_for_io_string(&executor, ob_id, &local_db_order.inputs).await?;
let output_vaults =
fetch_vaults_for_io_string(&executor, ob_id, &local_db_order.outputs).await?;

let order = RaindexOrder::try_from_local_db(
raindex_client.clone(),
chain_id,
local_db_order.clone(),
input_vaults,
output_vaults,
)?;
orders.push(order);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Store the OrderbookIdentifier instead of borrowing a temporary

let ob_id = &OrderbookIdentifier::new(...) takes a reference to a temporary that is dropped immediately, so the borrow does not live long enough. The compiler emits E0597: temporary value dropped while borrowed, preventing this module (and the PR) from compiling. Hold the identifier in a local and pass &ob_id to the async helpers.

-        let ob_id = &OrderbookIdentifier::new(chain_id, orderbook_cfg.address);
-        let local_db_orders = fetch_orders(&executor, ob_id, fetch_args.clone()).await?;
+        let ob_id = OrderbookIdentifier::new(chain_id, orderbook_cfg.address);
+        let local_db_orders =
+            fetch_orders(&executor, &ob_id, fetch_args.clone()).await?;

         for local_db_order in &local_db_orders {
-            let input_vaults =
-                fetch_vaults_for_io_string(&executor, ob_id, &local_db_order.inputs).await?;
-            let output_vaults =
-                fetch_vaults_for_io_string(&executor, ob_id, &local_db_order.outputs).await?;
+            let input_vaults =
+                fetch_vaults_for_io_string(&executor, &ob_id, &local_db_order.inputs).await?;
+            let output_vaults =
+                fetch_vaults_for_io_string(&executor, &ob_id, &local_db_order.outputs).await?;
🤖 Prompt for AI Agents
crates/common/src/raindex_client/orders.rs around lines 613 to 630: the code
currently borrows a temporary with let ob_id = &OrderbookIdentifier::new(...),
causing E0597 because the temporary is dropped across await points; change this
to create a local owned identifier (let ob_id =
OrderbookIdentifier::new(chain_id, orderbook_cfg.address);) and pass references
(&ob_id) into fetch_orders, fetch_vaults_for_io_string, and any other callers so
the referenced value lives long enough across the async/await boundaries.

Comment on lines +134 to +138
const statusResult = await getSyncStatus(
queryFn,
42161,
'0x2f209e5b67A33B8fE96E28f24628dF6Da301c8eB'
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM! API signature update is correct.

The addition of chain ID and orderbook address parameters correctly aligns with the updated getSyncStatus API signature. The hard-coded values (chain ID 42161 and orderbook address) are temporary placeholders consistent with the broader PR changes.

Optional: Consider extracting the hard-coded chain ID and orderbook address to constants at the top of the file, since they're used in multiple places (lines 136-137, 175, 200). This would improve maintainability and reduce the risk of inconsistent updates.

🤖 Prompt for AI Agents
In packages/webapp/src/routes/db-playground/+page.svelte around lines 134 to
138, there are hard-coded values for chain ID (42161) and the orderbook address
that are repeated elsewhere (lines ~175 and ~200); extract these into named
constants at the top of the file (e.g., CHAIN_ID and ORDERBOOK_ADDRESS), replace
each hard-coded occurrence with those constants, and ensure any imports or
linting rules are updated if needed so the constants are used consistently
across the file.

@findolor findolor merged commit 54360ec into main Nov 10, 2025
19 checks passed
@findolor findolor deleted the local-db-chain-id-orderbook-address branch November 10, 2025 11:00
@github-actions
Copy link
Copy Markdown
Contributor

@coderabbitai assess this PR size classification for the totality of the PR with the following criterias and report it in your comment:

S/M/L PR Classification Guidelines:

This guide helps classify merged pull requests by effort and complexity rather than just line count. The goal is to assess the difficulty and scope of changes after they have been completed.

Small (S)

Characteristics:

  • Simple bug fixes, typos, or minor refactoring
  • Single-purpose changes affecting 1-2 files
  • Documentation updates
  • Configuration tweaks
  • Changes that require minimal context to review

Review Effort: Would have taken 5-10 minutes

Examples:

  • Fix typo in variable name
  • Update README with new instructions
  • Adjust configuration values
  • Simple one-line bug fixes
  • Import statement cleanup

Medium (M)

Characteristics:

  • Feature additions or enhancements
  • Refactoring that touches multiple files but maintains existing behavior
  • Breaking changes with backward compatibility
  • Changes requiring some domain knowledge to review

Review Effort: Would have taken 15-30 minutes

Examples:

  • Add new feature or component
  • Refactor common utility functions
  • Update dependencies with minor breaking changes
  • Add new component with tests
  • Performance optimizations
  • More complex bug fixes

Large (L)

Characteristics:

  • Major feature implementations
  • Breaking changes or API redesigns
  • Complex refactoring across multiple modules
  • New architectural patterns or significant design changes
  • Changes requiring deep context and multiple review rounds

Review Effort: Would have taken 45+ minutes

Examples:

  • Complete new feature with frontend/backend changes
  • Protocol upgrades or breaking changes
  • Major architectural refactoring
  • Framework or technology upgrades

Additional Factors to Consider

When deciding between sizes, also consider:

  • Test coverage impact: More comprehensive test changes lean toward larger classification
  • Risk level: Changes to critical systems bump up a size category
  • Team familiarity: Novel patterns or technologies increase complexity

Notes:

  • the assessment must be for the totality of the PR, that means comparing the base branch to the last commit of the PR
  • the assessment output must be exactly one of: S, M or L (single-line comment) in format of: SIZE={S/M/L}
  • do not include any additional text, only the size classification
  • your assessment comment must not include tips or additional sections
  • do NOT tag me or anyone else on your comment

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 10, 2025

Tip

For best results, initiate chat on the files or code changes.

SIZE=L


🧠 Learnings used
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:42.275Z
Learning: For PR #1884, after each commit review, I should provide a new comment with a PR size report in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding irrelevant files such as lock files (package-lock.json, cargo.lock, etc.).

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:42.275Z
Learning: After each commit in PR #1884, I should provide a new comment with the PR size report in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`. The report should exclude irrelevant files such as lock files (e.g., package-lock.json, cargo.lock).

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:25:47.873Z
Learning: After each new commit review for rainlanguage/rain.orderbook repository, generate a PR size report in a separate comment with the format: "TOTAL=number ADDITIONS=number DELETIONS=number". This report should exclude irrelevant files such as lock files (e.g., package-lock.json, cargo.lock).

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:25:47.873Z
Learning: After each new commit review for rainlanguage/rain.orderbook repository, generate a PR size report in a separate comment with the exact format: "TOTAL=number\nADDITIONS=number\nDELETIONS=number". This report should exclude irrelevant files such as lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock).

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T22:14:22.646Z
Learning: For PR #1884 in rainlanguage/rain.orderbook, I must consistently report the PR size after EVERY new commit in the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number" without any formatting blocks. The report must exclude lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock) and can be included either as part of the review or as a separate comment.

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T22:14:22.646Z
Learning: For PR #1884 in rainlanguage/rain.orderbook, I must consistently report the PR size after EVERY new commit in the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number" without any additional text or formatting blocks. The report must exclude lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock) and can be included either as part of the review or as a separate comment.

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T22:46:08.530Z
Learning: For PR #1884 in rainlanguage/rain.orderbook, the PR size report should be the only content in the comment - no text before it, no text after it, no formatting blocks, just the raw report in the exact format: "TOTAL=number\nADDITIONS=number\nDELETIONS=number". The report must exclude lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock).

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR #1884 in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR #1884 in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR #1884 in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.

Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 1971
File: .github/workflows/vercel-docs-prod.yaml:32-34
Timestamp: 2025-07-11T12:30:09.245Z
Learning: findolor prefers not to pin Node versions explicitly in GitHub Actions workflows when using Nix with webapp-shell, considering the current setup sufficient for deterministic builds in the rainlanguage/rain.orderbook project.

Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 1971
File: .github/workflows/vercel-docs-prod.yaml:10-14
Timestamp: 2025-07-11T12:29:49.284Z
Learning: In GitHub Actions workflows for the rainlanguage/rain.orderbook project, findolor is comfortable with job names that may seem misleading (like "Deploy-Docs-Preview" in a production workflow) when there's only one job in the workflow, as the context makes it clear enough.

Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 1956
File: crates/common/src/fuzz/mod.rs:64-64
Timestamp: 2025-07-04T09:02:57.301Z
Learning: In rainlanguage/rain.orderbook, user findolor prefers to limit type consistency changes to only the parts directly related to the current work scope. For example, when updating chain_id fields from u64 to u32 in fuzz-related code, unrelated files like tauri-app wallet commands can remain as u64 if they serve different purposes and aren't part of the current changes.

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR #1884 in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.

Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2117
File: crates/js_api/src/gui/select_tokens.rs:421-424
Timestamp: 2025-09-02T08:04:34.729Z
Learning: User findolor in the rainlanguage/rain.orderbook codebase prefers not to change test code when tests are already passing, even if there appear to be type mismatches or potential issues. Working tests should be left alone unless there are actual errors.

Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2202
File: crates/common/src/raindex_client/local_db/sync.rs:33-34
Timestamp: 2025-10-14T07:51:55.148Z
Learning: In `crates/common/src/raindex_client/local_db/sync.rs`, the hard-coded `DEFAULT_SYNC_CHAIN_ID` constant (set to `SUPPORTED_LOCAL_DB_CHAINS[0]`) will be replaced with proper chain ID handling in downstream PRs as part of the multi-network/orderbook implementation.

Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:26:31.566Z
Learning: For PR #1884 and future PRs in rainlanguage/rain.orderbook repository, provide PR size reports in a separate comment with ONLY the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number", without any additional text or explanation. Reports should exclude irrelevant files such as lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock).

@coderabbitai coderabbitai Bot mentioned this pull request Dec 2, 2025
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants