Skip to content

Conversation

@CharlVS
Copy link
Collaborator

@CharlVS CharlVS commented Oct 26, 2025

Note

Introduces cross-platform event streaming (SSE on native, SharedWorker on web) and integrates it across SDK managers with caching and polling fallbacks to significantly reduce RPC usage.

  • Streaming (Framework/RPC):
    • Add KDF event streaming service (SSE on native via event_streaming_platform_io.dart, SharedWorker on web via assets/web/event_streaming_worker.js).
    • Define typed stream events (Balance, Orderbook, Network, Heartbeat, SwapStatus, OrderStatus, TxHistory, ShutdownSignal).
    • Add RPC streaming namespace and requests to enable/disable streams (stream::balance/orderbook/tx_history/network/heartbeat/swap_status/order_status/shutdown_signal).
    • Extend startup config with EventStreamingConfiguration (CORS, worker path).
  • SDK Integration:
    • Introduce EventStreamingManager and wire into DI; expose via KomodoDefiSdk.
    • Balance/Tx managers now consume streaming with robust fallback (polling + stale guards) and reduced RPC; confirmations refreshed periodically.
    • Add ActivatedAssetsCache with TTL; integrate into AssetManager, ActivationManager, and SDK config.
    • Persist and hydrate pubkeys via Hive; deduplicate in-flight pubkey requests; restart-safe state handling.
    • Add NftActivationService and helpers to wait for enabled assets/tickers.
  • Auth/Health:
    • Cache getUsers, prefer last user for getActiveUser, subscribe to shutdown signal stream; lengthen health-check interval; safer restart logic.
  • Market Data:
    • Add dispose() to repositories/providers; ensure DI disposes CoinPaprika resources; SparklineRepository.dispose() cleans up.
  • Protocols/Strategies:
    • Mark protocol/asset support for streaming; adjust ETH strategies to avoid enabling tx_history when not required; add requiresKdfTransactionHistory() to strategies.
  • Misc:
    • KDF native ops close HTTP client on dispose; CLI updater replaces checksums when commit changes; minor library name fix in coins config.

Written by Cursor Bugbot for commit 74d4999. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

Release Notes

  • Performance & Optimization

    • Implemented caching for wallet user data to reduce network requests
    • Optimized polling intervals for health checks and balance monitoring
    • Added request deduplication for concurrent operations
    • Introduced persistent data storage for faster application startup
    • Enhanced cache invalidation to maintain data consistency
  • Tests

    • Added new testing interface for health check functionality

…apters; hydrate on cold start\n\n- Add Hive adapters for stored pubkeys\n- Persist on fetch, hydrate before first RPC\n- Align balance polling to 60s and integrate with tx watcher\n\nBREAKING CHANGE: none
Copilot AI review requested due to automatic review settings October 26, 2025 22:00
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The PR adds caching and storage infrastructure to reduce redundant RPC calls and polling. It implements a user-list cache with 5-minute TTL in auth service, introduces Hive persistence for pubkey data with adapters and in-flight request deduplication in PubkeyManager, and replaces timer-based transaction polling with balance-change-driven subscription logic in TransactionHistoryManager.

Changes

Cohort / File(s) Summary
Auth Service Caching
packages/komodo_defi_local_auth/lib/src/auth/auth_service.dart, auth_service_operations_extension.dart
Added 5-minute TTL cache for wallet users with invalidation on user registration/deletion and sign-in. Health check timer increased from 5 to 5 minutes; active user retrieval now prefers cached last-emitted user to bypass RPC.
Test Infrastructure
packages/komodo_defi_local_auth/test/src/trezor/trezor_auth_service_test.dart
Added ensureKdfHealthy() public method to IAuthService interface; updated test scaffolding with pre-existing KDF user setup.
Balance Polling
packages/komodo_defi_sdk/lib/src/balances/balance_manager.dart
Increased balance polling interval from 30 seconds to 1 minute; minor log message formatting.
Dependency Injection
packages/komodo_defi_sdk/lib/src/bootstrap.dart
Wired BalanceManager into DI; passed balanceManager to TransactionHistoryManager constructor.
Pubkey Persistence Layer
packages/komodo_defi_sdk/lib/src/pubkeys/hive_pubkeys_adapters.dart
Added Hive persistence adapters: HiveStoredPubkey, HiveStoredPubkeyAdapter, HiveAssetPubkeysRecord, HiveAssetPubkeysRecordAdapter with factory conversions and registerPubkeysAdapters() function.
Pubkey Manager with Storage
packages/komodo_defi_sdk/lib/src/pubkeys/pubkey_manager.dart
Introduced pluggable PubkeysStorage dependency; added in-flight request deduplication map; enhanced getPubkeys to serve from cache, deduplicate concurrent requests, hydrate from storage, and persist asynchronously.
Pubkey Storage Interface
packages/komodo_defi_sdk/lib/src/pubkeys/pubkeys_storage.dart
Added abstract PubkeysStorage interface and HivePubkeysStorage implementation with savePubkeys() and listForWallet() methods for per-wallet, per-asset pubkey persistence.
Transaction History with Balance Subscription
packages/komodo_defi_sdk/lib/src/transaction_history/transaction_history_manager.dart
Replaced timer-based polling with balance-change-driven subscriptions; added BalanceManager dependency and internal subscription tracking; refactored streaming logic to trigger on balance changes rather than fixed intervals.

Sequence Diagrams

sequenceDiagram
    participant Consumer
    participant THM as TransactionHistoryManager
    participant BM as BalanceManager
    participant API as API Client
    
    Consumer->>THM: watch(assetId)
    THM->>BM: subscribe to balance changes
    activate THM
    THM->>API: initial poll transactions
    API-->>THM: transactions
    THM->>Consumer: emit transactions
    
    BM->>BM: balance updates
    BM-->>THM: emit BalanceInfo (changed)
    THM->>API: poll transactions (balance changed)
    API-->>THM: transactions
    THM->>Consumer: emit transactions
    deactivate THM
Loading
sequenceDiagram
    participant PubkeyManager
    participant Storage as HivePubkeysStorage
    participant Hive as Hive Box
    participant API as API Client
    
    PubkeyManager->>Storage: hydrate on watch start
    activate Storage
    Storage->>Hive: listForWallet(walletId)
    Hive-->>Storage: cached pubkeys
    Storage-->>PubkeyManager: hydrated pubkeys
    deactivate Storage
    PubkeyManager->>Consumer: emit cached pubkeys
    
    PubkeyManager->>API: fetch fresh pubkeys
    API-->>PubkeyManager: fresh pubkeys
    PubkeyManager->>Storage: persist asynchronously
    activate Storage
    Storage->>Hive: savePubkeys(...)
    Hive-->>Storage: saved
    deactivate Storage
    PubkeyManager->>Consumer: emit fresh pubkeys
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

  • PubkeyManager integration (pubkey_manager.dart): New storage layer with in-flight deduplication logic requires careful review of concurrent request handling and hydration-vs-fresh-data emission flow
  • TransactionHistoryManager refactor (transaction_history_manager.dart): Significant shift from timer-based to balance-driven polling; subscription lifecycle, edge cases (asset unwatched mid-poll), and interaction with BalanceManager need careful examination
  • Hive adapters (hive_pubkeys_adapters.dart, pubkeys_storage.dart): New persistence layer with nested data structure conversions; verify correct handling of optional fields and domain-to-persistence mapping
  • Cache invalidation logic (auth_service.dart): Verify TTL enforcement and cache invalidation on all relevant operations to prevent stale user state
  • Cross-module coordination: Bootstrap wiring and BalanceManager→TransactionHistoryManager dependency must be validated for correct lifecycle and cleanup

Possibly related PRs

Suggested labels

enhancement

Poem

🐰 A rabbit's ode to caching dreams

Five minutes to remember users past,
Hive stores pubkeys, built to last—
Balances whisper what to fetch,
No timers needed, a perfect sketch!
With storage blooming, fast we gleam,
Less RPC knocking on our beam. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "fix(rpc): minimise RPC usage with comprehensive caching and streaming support" is fully aligned with the changeset objectives. The title accurately captures the primary goal of reducing RPC calls through multiple mechanisms: user result caching with invalidation logic, pubkey persistence with storage adapters, request deduplication, and balance-driven subscriptions replacing fixed timers. The title is concise, specific enough for teammates to understand the core improvement, and avoids vague terminology. While "streaming support" could be marginally clearer (referring to balance subscriptions), it remains reasonably interpretable in context and does not mislead.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 perf/3238-reduce-rpc-spam

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors transaction history polling and adds pubkey persistence caching. The changes eliminate time-based polling in favor of balance-driven updates, add local storage for pubkeys to improve cold-start performance, and implement caching for user lists to reduce RPC calls.

Key changes:

  • Replaced time-based transaction history polling with balance-change-driven updates
  • Added Hive-based persistence for pubkeys with cold-start hydration
  • Introduced caching for wallet users list with 5-minute TTL

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
transaction_history_manager.dart Replaces timer-based polling with balance subscription; triggers history sync only when balance changes
pubkeys_storage.dart New storage interface and Hive implementation for persisting pubkeys
pubkey_manager.dart Adds storage integration, request deduplication, and hydration from persisted cache
hive_pubkeys_adapters.dart New Hive adapters for serializing pubkey data structures
bootstrap.dart Injects BalanceManager dependency into TransactionHistoryManager
balance_manager.dart Increases default polling interval from 30s to 1 minute
trezor_auth_service_test.dart Adds missing ensureKdfHealthy method to FakeAuthService mock
auth_service_operations_extension.dart Reduces health check frequency from 5 seconds to 5 minutes
auth_service.dart Implements 5-minute cache for user lists to reduce get_wallet_names calls

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@CharlVS CharlVS requested a review from takenagain October 26, 2025 22:01
@github-actions
Copy link
Contributor

github-actions bot commented Oct 26, 2025

Visit the preview URL for this PR (updated for commit 087d545):

https://kdf-sdk--pr262-perf-3238-reduce-rpc-0kkt2hl1.web.app

(expires Wed, 05 Nov 2025 00:06:12 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 9c1b6e6c010cf0b965c455ba7a69c4aedafa8a1d

@github-actions
Copy link
Contributor

github-actions bot commented Oct 26, 2025

Visit the preview URL for this PR (updated for commit 087d545):

https://komodo-playground--pr262-perf-3238-reduce-rpc-rbzvdd8v.web.app

(expires Wed, 05 Nov 2025 00:05:58 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 2bfedd77fdea45b25ba7c784416e81f177aa5c47

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

https://github.com/KomodoPlatform/komodo-defi-sdk-flutter/blob/0db04b262e32b40c1cbe97c3c16672cb5d6609d2/packages/komodo_defi_local_auth/lib/src/auth/auth_service_operations_extension.dart#L22-L33
P1 Badge Health check no longer queries KDF for active user

_checkKdfHealth() now calls getActiveUser() (lines 25‑33), but getActiveUser() was changed to return _lastEmittedUser whenever it is set (lines 285‑292). After a user signs in, health checks therefore just return the cached user and never hit the KDF RPC, so _emitAuthStateChange is never triggered when the active wallet changes outside this service. Clients depending on auth state updates will miss external sign-outs or user switches unless the health check reads from _getActiveUser() directly.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 205 to 209
Future<void> _persistPubkeys(Asset asset, AssetPubkeys pubkeys) async {
try {
final user = await _auth.currentUser;
if (user == null) return;
await _storage.savePubkeys(user.walletId, asset.id.id, pubkeys);

Choose a reason for hiding this comment

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

P1 Badge Persist pubkeys under wrong wallet when auth changes mid-fetch

getPubkeys persists fetched addresses via _persistPubkeys, but _persistPubkeys (shown here) reads await _auth.currentUser when it runs. If a user signs out and another signs in before the RPC completes, this function writes wallet A’s pubkeys into wallet B’s Hive record and repopulates the cache with stale data. Capturing the wallet id before starting the request and passing it through avoids cross‑wallet contamination.

Useful? React with 👍 / 👎.

This change ensures that pubkey data is correctly associated with the active wallet, preventing cross-wallet contamination. It also improves the accuracy of KDF health checks by bypassing cached user data.

Co-authored-by: charl <[email protected]>
@CharlVS
Copy link
Collaborator Author

CharlVS commented Oct 26, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 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.

@CharlVS CharlVS changed the title test(local-auth): add ensureKdfHealthy to FakeAuthService for Trezor tests fix(rpc): implement comprehensive data caching Oct 26, 2025
Copy link
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: 2

🧹 Nitpick comments (4)
packages/komodo_defi_sdk/lib/src/balances/balance_manager.dart (2)

78-82: Make polling interval configurable; default debug logs to false

  • Consider injecting polling interval (from config/constructor) to tune per environment.
  • Set enableDebugLogging to false by default to avoid warning spam in production.
-  final Duration _defaultPollingInterval = const Duration(minutes: 1);
+  final Duration _defaultPollingInterval = const Duration(minutes: 1); // consider DI/config override

-  static bool enableDebugLogging = true;
+  static bool enableDebugLogging = false;

380-387: Capture stack trace in polling errors

Log with stack trace for diagnosability.

-            } catch (e) {
+            } catch (e, s) {
               // Just log the error and continue with the last known balance
               // This prevents the stream from terminating on transient errors
               if (enableDebugLogging) {
-                _logger.warning(
-                  '[POLLING] Balance fetch failed for ${assetId.name}: $e',
-                );
+                _logger.warning(
+                  '[POLLING] Balance fetch failed for ${assetId.name}: $e',
+                  e,
+                  s,
+                );
               }
             }
packages/komodo_defi_sdk/lib/src/pubkeys/pubkey_manager.dart (1)

212-263: Remove unused non‑wallet‑stable helpers

_persistPubkeys and _hydrateFromStorage read _auth.currentUser and appear unused after adding wallet‑stable variants. Drop them to reduce confusion.

packages/komodo_defi_sdk/lib/src/pubkeys/pubkeys_storage.dart (1)

41-74: Reduce coupling to manager’s JSON shape

listForWallet returns a Map-of-Maps tailored to _hydrateFromStorage*. Consider returning typed AssetPubkeys (or adding getForWallet(...) -> Map<String, AssetPubkeys>) and let adapters handle domain mapping. This de-duplicates JSON shape logic and eases future schema changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 17311fc and 301ddb2.

📒 Files selected for processing (9)
  • packages/komodo_defi_local_auth/lib/src/auth/auth_service.dart (7 hunks)
  • packages/komodo_defi_local_auth/lib/src/auth/auth_service_operations_extension.dart (1 hunks)
  • packages/komodo_defi_local_auth/test/src/trezor/trezor_auth_service_test.dart (4 hunks)
  • packages/komodo_defi_sdk/lib/src/balances/balance_manager.dart (2 hunks)
  • packages/komodo_defi_sdk/lib/src/bootstrap.dart (2 hunks)
  • packages/komodo_defi_sdk/lib/src/pubkeys/hive_pubkeys_adapters.dart (1 hunks)
  • packages/komodo_defi_sdk/lib/src/pubkeys/pubkey_manager.dart (8 hunks)
  • packages/komodo_defi_sdk/lib/src/pubkeys/pubkeys_storage.dart (1 hunks)
  • packages/komodo_defi_sdk/lib/src/transaction_history/transaction_history_manager.dart (11 hunks)
🔇 Additional comments (24)
packages/komodo_defi_local_auth/lib/src/auth/auth_service_operations_extension.dart (2)

14-19: LGTM! Health check optimization is well-implemented.

Reducing the health check interval from 5 seconds to 5 minutes significantly reduces RPC load while maintaining adequate responsiveness. The explanatory comment clearly justifies the change.


25-26: Correct use of _getActiveUser() to bypass cache.

The health check correctly calls _getActiveUser() instead of the public getActiveUser() method to bypass the cached user optimization. This ensures external changes (e.g., another process modifying the active wallet) are detected. The comment clearly explains this important distinction.

packages/komodo_defi_local_auth/lib/src/auth/auth_service.dart (7)

116-120: LGTM! Cache infrastructure properly initialized.

The cache fields are appropriately scoped as private instance variables with a reasonable 5-minute TTL. This strikes a good balance between reducing RPC load and maintaining data freshness.


226-253: Cache-aside pattern correctly implemented.

The caching logic properly checks cache freshness before serving cached data and updates the cache after fetching from the RPC. The implementation is protected by the read lock, ensuring thread safety.


287-294: Effective optimization to reduce RPC calls.

Preferring _lastEmittedUser (which is kept current by health checks every 5 minutes) over making an immediate RPC call is a smart optimization. The fallback to _getActiveUser() ensures correctness when no user has been emitted yet.

Note: This means getActiveUser() could return data up to 5 minutes stale if an external process changes the active user, but this is an acceptable trade-off given the PR's goal of reducing RPC load.


216-216: Cache invalidation correctly placed.

Invalidating the users cache after successfully registering a new user ensures cache coherence when the user list changes.


374-374: Cache invalidation correctly placed.

Invalidating the users cache after successfully deleting a wallet ensures cache coherence when the user list changes.


417-420: LGTM! Clean cache invalidation helper.

Simple, focused helper method for clearing the cache state. Properly resets both the cache data and timestamp.


524-548: Reasonable KDF health recovery strategy.

The implementation handles the health check and recovery flow appropriately:

  • Checks KDF health first
  • Attempts recovery by restarting KDF in no-auth mode (since password is unavailable)
  • Gracefully handles errors by returning false instead of throwing

Note: Restarting in no-auth mode when a user exists will lose the authenticated session, but this is the best available recovery strategy without the user's password. The caller can then prompt for re-authentication if needed.

packages/komodo_defi_local_auth/test/src/trezor/trezor_auth_service_test.dart (2)

138-139: LGTM! Fake implementation correctly added.

The _FakeAuthService test double now implements the new ensureKdfHealthy() method from the IAuthService interface. Returning true (always healthy) is appropriate for a test fake, allowing tests to proceed without health check complications.


447-460: Test data improved with realistic KdfUser.

The test setup now includes a pre-existing KdfUser with isBip39Seed: true, making the test scenario more representative of actual usage. This better validates the "existing user" code path.

packages/komodo_defi_sdk/lib/src/bootstrap.dart (1)

243-253: DI wiring looks correct

BalanceManager is retrieved and passed into TransactionHistoryManager, and dependency order includes BalanceManager to avoid cycles. LGTM.

Also applies to: 256-262

packages/komodo_defi_sdk/lib/src/pubkeys/hive_pubkeys_adapters.dart (1)

36-42: No changes needed; BalanceInfo.total is correctly nullable

The BalanceInfo constructor accepts required Decimal? total (nullable), and the constructor assertion allows exactly 2 of 3 balance values to be provided. Setting total: null while providing spendable and unspendable satisfies this constraint and is the intended usage pattern.

packages/komodo_defi_sdk/lib/src/pubkeys/pubkey_manager.dart (1)

362-365: No changes required; the code implements equality semantics correctly

AssetPubkeys extends Equatable and properly overrides the props getter (lines 41–47) to include all fields: assetId, keys, availableAddressesCount, and syncStatus. Since Equatable provides value-based equality when props is correctly defined, the comparison first != hydrated at line 363 will work as intended and will not emit duplicates.

packages/komodo_defi_sdk/lib/src/pubkeys/pubkeys_storage.dart (1)

20-25: Hive initialization is guaranteed through proper SDK initialization flow, but no runtime safeguard exists for misuse

I confirmed that Hive.initFlutter() is called during bootstrap in ActivationConfigService registration, which occurs before PubkeyManager (and thus HivePubkeysStorage) is registered. The initialization sequence within bootstrap is correct: Hive is initialized before storage usage.

However, the code relies on the caller following the proper initialization pattern (KomodoDefiSdk.initialize() before any storage usage). Since HivePubkeysStorage._openBox() has no explicit runtime check verifying Hive is initialized, misuse outside the SDK's initialization context would fail silently. The review's concern about verifying initialization in all app entry points is valid from a defensive programming perspective.

packages/komodo_defi_sdk/lib/src/transaction_history/transaction_history_manager.dart (9)

34-47: LGTM! Constructor properly wired for balance-driven polling.

The addition of BalanceManager as a required parameter correctly supports the new balance-driven polling mechanism. The dependency is properly stored and will be used to subscribe to balance changes.

Also applies to: 61-61


64-65: LGTM! State management for balance-driven polling.

The new state fields properly track balance subscriptions and last observed values per asset, enabling efficient change detection.


69-70: Comment correctly positioned.

The comment on line 69 now accurately describes the _maxPollingRetries constant on line 70, resolving the past review concern about comment positioning.


78-94: LGTM! Proper cleanup of balance subscriptions.

The method correctly cancels all balance subscriptions and clears related state before closing stream controllers.


248-273: LGTM! Prevents duplicate balance subscriptions.

The check on line 258 ensures balance subscriptions are created only once per asset, preventing resource leaks.


359-360: LGTM! Good defensive check.

The early exit prevents unnecessary work if the asset is no longer being watched, improving efficiency.


429-432: Balance change detection is focused on transaction-relevant fields.

The logic only compares total and spendable to detect changes, which aligns with the PR objective of reducing RPC spam by triggering polls only when meaningful balance changes occur.

Note: If BalanceInfo has other fields that could change independently, they won't trigger polling. Verify this is acceptable for your use case.


440-445: LGTM! Proper cleanup of asset-specific balance state.

The method correctly cancels the balance subscription and cleans up related state for the specific asset.


116-118: LGTM! Formatting improvements for readability.

The multi-line formatting of pagination parameters and transaction conversions improves code readability without changing functionality.

Also applies to: 146-148, 206-212, 220-222, 296-302, 310-312, 353-355, 363-365

@GLEECBTC GLEECBTC deleted a comment from cursor bot Oct 26, 2025
cursor[bot]

This comment was marked as outdated.

- Wire SDK `ActivatedAssetsCache` into activation/coins flows:
  updates across `CoinsBloc`, `AssetOverviewBloc`, custom token import, and
  `sdk_auth_activation_extension` to reuse activation state instead of re-querying.
- Debounce/polish polling in `portfolio_growth_bloc` and `profit_loss_bloc`
  to prevent overlapping requests.
- Remove duplicate activation/balance checks in maker/taker validators and forms.
- Consolidate repeated calls in `mm2_api`/`mm2_api_nft`/`rpc_native`; prefer cached values.
- Reduce startup RPCs in `app_bootstrapper`; stop background timers in
  `window_close_handler` on app close to avoid trailing calls.
- Add shared intervals in `shared/constants`; introduce
  `lib/shared/utils/activated_assets_cache.dart` for app-specific helpers.
- No UI changes; measurable reduction in RPC volume and improved responsiveness.

Refs #3238
…on; expose streaming API in framework and rpc methods
- Replace string-based event types with sealed class hierarchy
- Create typed event classes for all stream types (Balance, Orderbook, Network, Heartbeat, SwapStatus, OrderStatus, TxHistory, ShutdownSignal)
- Use private enum for internal string mapping while exposing typed API
- Make StreamEnableResponse generic to link responses to event types
- Update event_streaming_service with type-safe filtering methods
- Organize events into separate files using part directives
- Enable exhaustive pattern matching with switch expressions

Benefits:
- Compile-time type safety eliminates string-based checks
- Better IDE support with autocomplete and type hints
- Reduced runtime errors from type mismatches
- Clearer public API with explicit event types
cursor[bot]

This comment was marked as outdated.

…ment

- Create EventStreamingManager in komodo_defi_sdk package
- Implement automatic stream lifecycle handling (enable/disable)
- Add reference counting for shared stream subscriptions
- Support all event types: balance, orderbook, tx history, swap status, order status, network, heartbeat, and shutdown signals
- Reduce boilerplate with generic _subscribeToStream method using template method pattern
- Register manager in DI container for internal use by domain managers
- Manager is not publicly exposed, intended for use by domain-specific managers to provide real-time updates
cursor[bot]

This comment was marked as outdated.

Replace periodic polling with real-time event streaming in BalanceManager
and TransactionHistoryManager to reduce RPC spam and improve efficiency.

Changes:
- BalanceManager: Replace 1-minute polling interval with balance event streaming
- TransactionHistoryManager: Replace balance-driven polling with TX history event streaming
- Bootstrap: Inject EventStreamingManager into both managers
- Remove polling configuration (intervals, retry counters, debug flags)
- Fix shouldEnableTransactionHistory to always return true for streaming support

Benefits:
- Eliminates periodic RPC calls every 60 seconds
- Real-time updates instead of up to 1-minute delays
- Better resource utilization (updates only when data changes)
- Automatic reconnection and error handling via EventStreamingManager

Refs: #3238
cursor[bot]

This comment was marked as outdated.

The _waitForCoinAvailability method was failing to verify asset activation
because isAssetActive() was using cached data instead of fetching fresh data
from the backend. This caused transaction history to fail with a connection
error even though assets were successfully activated.

Changes:
- Add forceRefresh parameter to ActivationManager.isAssetActive()
- Update SharedActivationCoordinator._waitForCoinAvailability() to force
  refresh on each availability check
- This ensures we bypass the 2-second cache TTL and get real-time data

Fixes issue where transaction history shows 'Connection to Komodo servers
are failing' error after asset activation completes successfully.
cursor[bot]

This comment was marked as outdated.

… subscriptions

The balance and transaction history event subscriptions were using
asset.id.name (the human-friendly display name like 'Bitcoin') instead of
asset.id.id (the config ID like 'BTC-segwit'). This caused the RPC enable
streaming calls to fail because the backend expects the config ID.

Changes:
- BalanceManager: Use assetId.id instead of assetId.name for subscribeToBalance
- TransactionHistoryManager: Use asset.id.id instead of asset.id.name for subscribeToTxHistory
- Update event filtering to match using config ID as well

This fixes the 'Failed to start balance watcher' errors and resolves the
transaction history connection error.
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

…dk-flutter into perf/3238-reduce-rpc-spam

# Conflicts:
#	packages/komodo_defi_framework/lib/komodo_defi_framework.dart
#	packages/komodo_defi_local_auth/lib/src/auth/auth_service.dart
cursor[bot]

This comment was marked as outdated.

@CharlVS CharlVS changed the title fix(rpc): implement comprehensive data caching fix(rpc): minimise RPC usage with comprehensive caching and streaming support Oct 29, 2025
This change refactors the transaction comparison logic in `InMemoryTransactionStorage` to ensure that all transactions are available during comparison. This prevents potential exceptions and improves the stability of the transaction history storage.

Co-authored-by: Cursor Agent <[email protected]>
required void Function(Object? data) onMessage,
IKdfHostConfig? hostConfig,
}) {
final IKdfHostConfig cfg = hostConfig!;
Copy link

Choose a reason for hiding this comment

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

Bug: Null Assertion Error in Configuration Handling

The hostConfig parameter is declared as nullable (IKdfHostConfig?) but is immediately force-unwrapped. This can lead to a runtime null assertion error if hostConfig is null when connectEventStream is called.

Fix in Cursor Fix in Web

@ca333 ca333 merged commit c963681 into dev Oct 29, 2025
5 of 8 checks passed
ca333 added a commit that referenced this pull request Oct 30, 2025
#269)

* fix(rpc): minimise RPC usage with comprehensive caching and streaming support (#262)

* feat(pubkeys): persist AssetPubkeys across sessions using Hive TypeAdapters; hydrate on cold start\n\n- Add Hive adapters for stored pubkeys\n- Persist on fetch, hydrate before first RPC\n- Align balance polling to 60s and integrate with tx watcher\n\nBREAKING CHANGE: none

* chore(format): run dart format on pubkey persistence and balance manager files

* perf(sdk): dedupe pubkeys/address fetch, cache-first hydrate; throttle health checks; cache wallet names (#3238)

* test(local-auth): add ensureKdfHealthy to FakeAuthService for Trezor tests

* Refactor: Wallet-aware pubkey persistence and retrieval

This change ensures that pubkey data is correctly associated with the active wallet, preventing cross-wallet contamination. It also improves the accuracy of KDF health checks by bypassing cached user data.

Co-authored-by: charl <[email protected]>

* Refactor: Improve pubkey and balance fetching logic

Co-authored-by: charl <[email protected]>

* fix: market data resource improvements

* perf(assets): cache activated assets and coalesce activation checks

- Wire SDK `ActivatedAssetsCache` into activation/coins flows:
  updates across `CoinsBloc`, `AssetOverviewBloc`, custom token import, and
  `sdk_auth_activation_extension` to reuse activation state instead of re-querying.
- Debounce/polish polling in `portfolio_growth_bloc` and `profit_loss_bloc`
  to prevent overlapping requests.
- Remove duplicate activation/balance checks in maker/taker validators and forms.
- Consolidate repeated calls in `mm2_api`/`mm2_api_nft`/`rpc_native`; prefer cached values.
- Reduce startup RPCs in `app_bootstrapper`; stop background timers in
  `window_close_handler` on app close to avoid trailing calls.
- Add shared intervals in `shared/constants`; introduce
  `lib/shared/utils/activated_assets_cache.dart` for app-specific helpers.
- No UI changes; measurable reduction in RPC volume and improved responsiveness.

Refs #3238

* feat(streaming): add typed stream RPCs and web SharedWorker integration; expose streaming API in framework and rpc methods

* feat(web): package event_streaming_worker.js in framework assets and load via package path

* fix(web): correct SharedWorker path to package asset under assets/web/

* refactor(streaming): improve type safety with sealed event classes

- Replace string-based event types with sealed class hierarchy
- Create typed event classes for all stream types (Balance, Orderbook, Network, Heartbeat, SwapStatus, OrderStatus, TxHistory, ShutdownSignal)
- Use private enum for internal string mapping while exposing typed API
- Make StreamEnableResponse generic to link responses to event types
- Update event_streaming_service with type-safe filtering methods
- Organize events into separate files using part directives
- Enable exhaustive pattern matching with switch expressions

Benefits:
- Compile-time type safety eliminates string-based checks
- Better IDE support with autocomplete and type hints
- Reduced runtime errors from type mismatches
- Clearer public API with explicit event types

* feat(sdk): add internal event streaming manager with lifecycle management

- Create EventStreamingManager in komodo_defi_sdk package
- Implement automatic stream lifecycle handling (enable/disable)
- Add reference counting for shared stream subscriptions
- Support all event types: balance, orderbook, tx history, swap status, order status, network, heartbeat, and shutdown signals
- Reduce boilerplate with generic _subscribeToStream method using template method pattern
- Register manager in DI container for internal use by domain managers
- Manager is not publicly exposed, intended for use by domain-specific managers to provide real-time updates

* perf: eliminate RPC polling by using event streaming

Replace periodic polling with real-time event streaming in BalanceManager
and TransactionHistoryManager to reduce RPC spam and improve efficiency.

Changes:
- BalanceManager: Replace 1-minute polling interval with balance event streaming
- TransactionHistoryManager: Replace balance-driven polling with TX history event streaming
- Bootstrap: Inject EventStreamingManager into both managers
- Remove polling configuration (intervals, retry counters, debug flags)
- Fix shouldEnableTransactionHistory to always return true for streaming support

Benefits:
- Eliminates periodic RPC calls every 60 seconds
- Real-time updates instead of up to 1-minute delays
- Better resource utilization (updates only when data changes)
- Automatic reconnection and error handling via EventStreamingManager

Refs: #3238

* fix(cache): address PR review issues - error handling and race conditions

- Health check: log transient RPC failures instead of triggering false sign-outs
- ActivatedAssetsCache: fix race condition using generation counter and Completer pattern
- NFT activation: aggregate and report all errors instead of only the last one
- Auth service: document 5-minute user cache staleness trade-off

Refs: #262

* chore: add event streaming logging

* fix(rpc): address critical review feedback on caching implementation

- Fix incorrect unawaited() usage in pubkey_manager by properly extracting Future
- Add eagerError: false to event_streaming_manager dispose for robust cleanup
- Replace unsafe String cast with whereType<String>() in pubkeys_storage
- Add race condition check in transaction_history_manager _startStreaming
- Capture timestamp at fetch start in activated_assets_cache for accurate TTL
- Add error handling to sparkline_repository dispose to ensure all cleanup

* perf(auth): use shutdown event streaming to minimize RPC polling

Subscribe to KDF shutdown signals to immediately detect when KDF shuts down,
eliminating the need for frequent polling. This provides near-instant shutdown
detection (< 1 second) compared to periodic health checks.

- Add shutdown signal subscription in KdfAuthService
- Subscribe to shutdown events and immediately update auth state
- Enable shutdown signal stream via RPC on initialization
- Clean up subscription on dispose
- Health checks now serve as backup for edge cases

Benefits:
- Reduces getWalletNames RPC calls significantly
- Provides instant user sign-out on KDF shutdown
- Maintains graceful degradation if streaming unavailable

* feat(rpc): optimize initial balance/history for newly created wallets

- Assume zero balance for first-time asset enablement in new wallets
- Assume empty transaction history for first-time asset enablement in new wallets
- Detect new wallets by absence of any asset activation history
- Avoids unnecessary RPC spam when activating first assets in new wallets
- Does NOT apply to imported wallets (they have activation history)
- Uses AssetHistoryStorage to track which assets have been enabled per wallet
- Wire up shared AssetHistoryStorage instance in SDK bootstrap

* fix(auth): track imported vs created wallets to prevent incorrect optimizations

- Add 'isImported' metadata to KdfUser during registration
- Pass mnemonic presence to _registerNewUser to determine if imported
- Update balance/history managers to check isImported flag
- Prevents incorrectly assuming zero balance for imported wallets
- Optimization now only applies to genuinely new wallets (not imported)

BREAKING: Imported wallets will now correctly fetch real balances/history
on first use instead of incorrectly showing zero

* fix: remove errors from KDF merge

* chore: roll `coins`

* fix: misc streaming fixes

* feat(sdk): add event streaming support for task status updates

- Add event streaming service and configuration
- Implement task event handling and unknown event fallback
- Add RPC task shepherd method for task status monitoring
- Update balance manager to support event-driven updates
- Add platform-specific event streaming implementations
- Enhance sync status with event streaming capabilities

This reduces RPC polling by leveraging KDF event streaming for task status updates.

* fix(activation): force cache refresh when verifying asset availability

The _waitForCoinAvailability method was failing to verify asset activation
because isAssetActive() was using cached data instead of fetching fresh data
from the backend. This caused transaction history to fail with a connection
error even though assets were successfully activated.

Changes:
- Add forceRefresh parameter to ActivationManager.isAssetActive()
- Update SharedActivationCoordinator._waitForCoinAvailability() to force
  refresh on each availability check
- This ensures we bypass the 2-second cache TTL and get real-time data

Fixes issue where transaction history shows 'Connection to Komodo servers
are failing' error after asset activation completes successfully.

* fix(streaming): use asset config ID instead of display name for event subscriptions

The balance and transaction history event subscriptions were using
asset.id.name (the human-friendly display name like 'Bitcoin') instead of
asset.id.id (the config ID like 'BTC-segwit'). This caused the RPC enable
streaming calls to fail because the backend expects the config ID.

Changes:
- BalanceManager: Use assetId.id instead of assetId.name for subscribeToBalance
- TransactionHistoryManager: Use asset.id.id instead of asset.id.name for subscribeToTxHistory
- Update event filtering to match using config ID as well

This fixes the 'Failed to start balance watcher' errors and resolves the
transaction history connection error.

* perf: reduce RPC spam in activation strategies and managers

* fix(auth-service): update cache alongside storage for metadata updates

* chore: roll KDF to release preview

Roll KDF to the `dev` branch version which will be used for KW release.

* fix(stream): normalize KDF stream _type parsing for suffixed IDs; format modified files

* fix: use correct streaming worker js path

* fix: tx history streaming

* fix: improve robustness of event parsing

* fix: backwards compatibility for KDF API status

* Refactor: Improve transaction comparison logic (#268)

This change refactors the transaction comparison logic in `InMemoryTransactionStorage` to ensure that all transactions are available during comparison. This prevents potential exceptions and improves the stability of the transaction history storage.

Co-authored-by: Cursor Agent <[email protected]>

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Francois <[email protected]>

* fix config

* fix timers leak

* fix sse

---------

Co-authored-by: Nitride <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Francois <[email protected]>
@coderabbitai coderabbitai bot mentioned this pull request Oct 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants