Skip to content

feat(auth): poll trezor connection status and sign out when disconnected#126

Merged
CharlVS merged 19 commits intodevfrom
feat/trezor-connection-status
Aug 13, 2025
Merged

feat(auth): poll trezor connection status and sign out when disconnected#126
CharlVS merged 19 commits intodevfrom
feat/trezor-connection-status

Conversation

@takenagain
Copy link
Copy Markdown
Contributor

@takenagain takenagain commented Jul 7, 2025

Signs the user out if Trezor connectivity is lost - trezor_connection_status reports device disconnected.

Summary by CodeRabbit

  • New Features

    • Real-time Trezor connection monitoring with automatic sign-out on disconnect.
    • Connection status enum (Connected, Disconnected, Busy, Unreachable, Unknown).
    • Data models for Trezor device info and user-action payloads.
    • RPC method to query and stream Trezor connection status.
  • Improvements

    • Auth flows integrated with connection monitoring, DI for dependencies, and more robust lifecycle/cleanup.
  • Utilities

    • Generic polling utility with backoff and error-handling options.
  • Tests

    • Comprehensive unit tests for auth service, connection monitor, and repository.

@takenagain takenagain self-assigned this Jul 7, 2025
@takenagain takenagain added the enhancement New feature or request label Jul 7, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

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

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds Trezor connection-status RPC, parsed enum, repository polling/streaming, a TrezorConnectionMonitor class, wiring of monitoring into TrezorAuthService, new Freezed trezor types, a generic poll utility, test suites, and small example/packaging updates.

Changes

Cohort / File(s) Change Summary
Library exports
packages/komodo_defi_local_auth/lib/src/trezor/_trezor_index.dart, packages/komodo_defi_types/lib/komodo_defi_type_utils.dart, packages/komodo_defi_types/lib/src/types.dart
Added exports for trezor_connection_monitor.dart, trezor_connection_status.dart, src/utils/poll_utils.dart, and exported new trezor type files.
Auth service
packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart
Constructor accepts injectable TrezorConnectionMonitor, FlutterSecureStorage, and password generator; added _start/_stop monitoring helpers; async dispose() and signOut() now stop/dispose monitor; integrated monitoring start after successful auth (including stream path) and stop on sign-out/disconnection; refactored password generation.
Connection monitor & status
packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart, packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_status.dart
New TrezorConnectionMonitor class (start/stop/dispose, callbacks, logging, lastKnownStatus/isMonitoring) and new TrezorConnectionStatus enum with parsing, labels, apiValue, and boolean helpers.
Repository
packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart
Added getConnectionStatus and watchConnectionStatus that call the RPC, parse into TrezorConnectionStatus, provide polled streaming with change filtering and termination rules; cleaned polling/init timer handling and adjusted error behavior.
RPC namespace
packages/komodo_defi_rpc_methods/lib/src/rpc_methods/trezor/trezor_rpc_namespace.dart
Added connectionStatus RPC method plus TrezorConnectionStatusRequest/TrezorConnectionStatusResponse; removed in-file device/user-action types and import them from komodo_defi_types.
Types — trezor models & generated
packages/komodo_defi_types/lib/src/trezor/trezor_device_info.dart, .../trezor_device_info.freezed.dart, .../trezor_device_info.g.dart, packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.dart, .../trezor_user_action_data.freezed.dart, .../trezor_user_action_data.g.dart
Added TrezorDeviceInfo and TrezorUserActionData (with TrezorUserActionType) Freezed data models and their generated JSON serialization files.
Utils
packages/komodo_defi_types/lib/src/utils/poll_utils.dart
Added generic poll utility for repeated async polling with backoff, timeout, error handling, and onPoll callback.
Example / SDK instrumentation & deps
packages/komodo_defi_sdk/example/lib/blocs/auth/auth_bloc.dart, packages/komodo_defi_sdk/example/lib/blocs/auth/trezor_auth_mixin.dart, packages/komodo_defi_sdk/example/pubspec.yaml
Added logging import and statements, reordered part directives, added cancellation event handler, and updated example dependencies to use local komodo_defi_rpc_methods and logging.
Tests
packages/komodo_defi_local_auth/test/src/trezor/*
Added comprehensive unit tests for TrezorAuthService, TrezorConnectionMonitor, and TrezorRepository with fakes/mocks and RPC response helpers.
Misc
packages/komodo_defi_local_auth/.gitignore
Added web/ to .gitignore.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant TrezorAuthService
    participant TrezorConnectionMonitor
    participant TrezorRepository
    participant RPCClient

    App->>TrezorAuthService: signIn/register or auth stream
    TrezorAuthService->>TrezorConnectionMonitor: _startConnectionMonitoring(devicePubkey?)
    TrezorConnectionMonitor->>TrezorRepository: watchConnectionStatus(devicePubkey, pollInterval, maxDuration)
    loop polling
        TrezorRepository->>RPCClient: connectionStatus request
        RPCClient-->>TrezorRepository: status response
        TrezorRepository-->>TrezorConnectionMonitor: TrezorConnectionStatus
        TrezorConnectionMonitor-->>TrezorAuthService: onStatusChanged / onConnectionLost / onConnectionRestored
        alt onConnectionLost
            TrezorAuthService->>TrezorAuthService: _signOutCurrentTrezorUser() / stop monitoring
        end
    end
    App->>TrezorAuthService: signOut / dispose
    TrezorAuthService->>TrezorConnectionMonitor: _stopConnectionMonitoring()/dispose()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Possibly related PRs

Suggested labels

QA

Suggested reviewers

  • smk762
  • CharlVS

Poem

In my burrow I hop through code so spry,
I poll and I listen as Trezors sigh.
When status says "lost" I thump and I turn,
I tidy sessions and watch connections burn.
Happy bytes and safe sign-outs — hop, hop, bye-bye! 🐇✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/trezor-connection-status

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@takenagain takenagain added this to the KW 0.10.0 milestone Jul 7, 2025
@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jul 7, 2025

Visit the preview URL for this PR (updated for commit 4ec1b11):

https://komodo-defi-sdk--pr126-feat-trezor-connecti-wzjic6mx.web.app

(expires Tue, 19 Aug 2025 18:46:58 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 7f9f5ac39928f333b6e8fcefb7138575e24ed347

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

🔭 Outside diff range comments (1)
packages/komodo_defi_local_auth/lib/src/trezor/trezor_initialization_state.dart (1)

26-69: Consider replacing fragile status string literals with a sealed enum

response.status is compared against raw strings ('Ok', 'Error', …). A single typo or backend change will silently route the logic to the default branch and surface as a generic “Unknown status” error.

- switch (response.status) {
-   case 'Ok':
+ switch (TrezorRpcStatus.from(response.status)) {
+   case TrezorRpcStatus.ok:

Advantages:
• Compile-time exhaustiveness checks
• IDE autocomplete instead of magic strings
• Easier refactors when the backend adds a status

If a direct enum mapping from the RPC layer isn’t feasible, at least centralise the string constants.

🧹 Nitpick comments (4)
packages/komodo_defi_types/lib/komodo_defi_type_utils.dart (1)

12-12: Export looks good – verify public API docs reference the new util

poll_utils.dart will now be part of the public surface. Ensure the package-level README or API docs mention the new poll helper so downstream packages know it exists.

packages/komodo_defi_types/lib/src/trezor/trezor_device_info.dart (2)

4-4: non_abstract_class_inherits_abstract_member ignore is redundant

freezed-generated classes no longer require this suppression; leaving it in bloats lints.

-// ignore_for_file: non_abstract_class_inherits_abstract_member

14-24: Expose toJson() for symmetry

The class defines fromJson manually but relies on the generated toJson method implicitly. For clarity and discoverability, expose it explicitly:

   /// Construct a [TrezorDeviceInfo] from json.
   factory TrezorDeviceInfo.fromJson(JsonMap json) =>
       _$TrezorDeviceInfoFromJson(json);

+  /// Convert this object to json.
+  JsonMap toJson() => _$TrezorDeviceInfoToJson(this);

This prevents consumers from wondering whether a toJson exists and avoids relying on generated-member discovery.

packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_status.dart (1)

19-32: Consider string casing consistency between parsing and display.

The fromString method expects lowercase input ('connected', 'disconnected'), while the value getter returns capitalized strings ('Connected', 'Disconnected'). This may be intentional for display purposes, but ensure this design is consistent with API expectations.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce68c7a and 32c0006.

📒 Files selected for processing (16)
  • packages/komodo_defi_local_auth/lib/src/trezor/_trezor_index.dart (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (8 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_status.dart (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_initialization_state.dart (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (2 hunks)
  • packages/komodo_defi_rpc_methods/lib/src/rpc_methods/trezor/trezor_rpc_namespace.dart (4 hunks)
  • packages/komodo_defi_types/lib/komodo_defi_type_utils.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/trezor/trezor_device_info.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/trezor/trezor_device_info.freezed.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/trezor/trezor_device_info.g.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.freezed.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.g.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/types.dart (1 hunks)
  • packages/komodo_defi_types/lib/src/utils/poll_utils.dart (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/komodo_defi_rpc_methods/lib/src/rpc_methods/trezor/trezor_rpc_namespace.dart (1)
Learnt from: takenagain
PR: KomodoPlatform/komodo-defi-sdk-flutter#70
File: packages/komodo_defi_rpc_methods/lib/src/rpc_methods/swaps/legacy/cancel_order.dart:8-9
Timestamp: 2025-06-02T12:44:56.953Z
Learning: Legacy RPC methods in the Komodo DeFi SDK (located in `/legacy/` subdirectories) intentionally use `mmrpc: null` in their constructors, unlike modern RPC methods that use `mmrpc: "2.0"`. This is by design and should not be changed to maintain backward compatibility.
⏰ 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). (2)
  • GitHub Check: build_and_preview_sdk_example_preview
  • GitHub Check: build_and_preview_playground_preview
🔇 Additional comments (17)
packages/komodo_defi_local_auth/lib/src/trezor/trezor_initialization_state.dart (1)

4-4: Import correctly points to relocated types – good catch

Switching the TrezorDeviceInfo source to komodo_defi_types keeps the layer-boundaries clean after the refactor.

packages/komodo_defi_types/lib/src/types.dart (1)

59-60: 👍 Centralising Trezor types improves reuse

Exporting trezor_device_info.dart and trezor_user_action_data.dart from the shared types package removes duplication across modules and simplifies dependency graphs.

packages/komodo_defi_local_auth/lib/src/trezor/_trezor_index.dart (1)

7-8: New exports keep the private index in sync

trezor_connection_monitor.dart and trezor_connection_status.dart are now reachable from the internal barrel. No issues spotted.

packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.g.dart (1)

1-30: Generated JSON serialization code looks correct.

The auto-generated JSON serialization and deserialization logic properly handles the enum mapping and nullable fields as expected.

packages/komodo_defi_types/lib/src/trezor/trezor_device_info.g.dart (1)

1-26: Generated JSON serialization code looks correct.

The auto-generated JSON serialization and deserialization logic properly handles both required and optional fields with appropriate field mapping.

packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_status.dart (1)

50-61: Helper methods implement correct status logic.

The boolean getters appropriately categorize connection states:

  • isAvailable correctly identifies only connected state
  • isUnavailable properly includes disconnected and unreachable states
  • shouldContinueMonitoring correctly excludes only disconnected state for polling control
packages/komodo_defi_types/lib/src/utils/poll_utils.dart (1)

10-52: Well-designed polling utility with robust error handling.

The implementation correctly handles:

  • Timeout enforcement with stopwatch
  • Configurable backoff strategies
  • Selective error continuation
  • Proper attempt tracking and callbacks

The logic flow and error handling patterns are appropriate for a generic polling utility.

packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.dart (3)

9-17: Enum implementation with proper JSON serialization.

The TrezorUserActionType enum correctly uses @JsonEnum with valueField to map enum values to their string representations for JSON serialization.


22-26: Validation logic correctly enforces data consistency.

The @Assert annotation properly validates that:

  • PIN is provided when actionType is TrezorPin
  • Passphrase is provided when actionType is TrezorPassphrase

This prevents invalid state combinations at compile time.


28-36: Well-structured data class with appropriate serialization.

The TrezorUserActionData class correctly uses:

  • @freezed for immutable data structure
  • @JsonSerializable with snake_case field naming for API consistency
  • Proper factory method for JSON deserialization
packages/komodo_defi_types/lib/src/trezor/trezor_device_info.freezed.dart (1)

1-245: LGTM! Generated Freezed file.

This is a properly generated Freezed file with standard implementations for immutable data classes.

packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.freezed.dart (1)

1-203: LGTM! Generated Freezed file with proper validation.

This generated file includes appropriate validation logic ensuring PIN/passphrase requirements are met based on the action type.

packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (1)

216-219: Potential redundant monitoring stop operations.

When connection is lost, _signOutCurrentTrezorUser is called (line 218), which stops monitoring (line 236). However, the monitor is still actively running when this happens. Consider whether this could cause any side effects.

Verify the behavior when stopMonitoring is called while the monitor is actively processing a disconnection event.

Also applies to: 232-237

packages/komodo_defi_rpc_methods/lib/src/rpc_methods/trezor/trezor_rpc_namespace.dart (4)

3-4: LGTM! Import refactoring aligns with centralized type management.

The imports properly reference the shared types from the komodo_defi_types package, which improves code organization and reusability across the codebase.


110-121: LGTM! Well-documented connection status method.

The implementation follows the established pattern of other RPC methods in the namespace:

  • Proper documentation with clear description
  • Consistent method signature with optional parameters
  • Uses the correct request/response types
  • Follows the same execution pattern as other methods

210-227: LGTM! Request class follows established conventions.

The TrezorConnectionStatusRequest class properly:

  • Extends BaseRequest with correct generic types
  • Uses modern MMRPC version '2.0' (consistent with other non-legacy methods)
  • Handles optional devicePubkey parameter correctly in JSON serialization
  • Uses appropriate fromJson parsing method for the response

322-341: LGTM! Response class handles JSON parsing correctly.

The TrezorConnectionStatusResponse class demonstrates good practices:

  • Uses valueOrNull for potentially null mmrpc field
  • Uses value for required status field with proper error handling
  • Follows the expected JSON structure with result.status nesting
  • Implements proper toJson serialization

Comment thread packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart Outdated
@takenagain takenagain marked this pull request as ready for review July 31, 2025 23:06
Copilot AI review requested due to automatic review settings July 31, 2025 23:06

This comment was marked as outdated.

@takenagain takenagain requested a review from Copilot August 8, 2025 12:07

This comment was marked as outdated.

@takenagain takenagain marked this pull request as ready for review August 12, 2025 12:47
@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 12, 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.

cursor[bot]

This comment was marked as outdated.

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: 1

♻️ Duplicate comments (3)
packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (1)

208-249: Add defensive check for null last value before the while loop.

While the initial try-catch ensures last is assigned, adding a defensive check would make the code more robust against future modifications.

+   if (last == null) {
+     // Defensive: should not happen, but ensures safety
+     yield TrezorConnectionStatus.unreachable;
+     return;
+   }
+
    while (last.shouldContinueMonitoring && stopwatch.elapsed < maxDuration) {
packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart (1)

66-71: Don't treat every stream error as a disconnection; classify errors before signing the user out.

Right now any error while listening triggers onConnectionLost (unless already disposed), which risks false sign-outs from transient issues. Add an error classifier and only trigger sign-out for genuine connection-loss errors. This matches the prior feedback and avoids unnecessary logouts.

Apply this diff to gate the callback on connection-related errors:

-          onError: (Object error, StackTrace stackTrace) {
-            _log.severe('Error monitoring Trezor connection: $error', error, stackTrace);
-            // Only call onConnectionLost if this is a real connection error, not a disposal
-            if (_connectionSubscription != null) {
-              onConnectionLost?.call();
-            }
-          },
+          onError: (Object error, StackTrace stackTrace) {
+            _log.severe('Error monitoring Trezor connection: $error', error, stackTrace);
+            // Only treat specific errors as connection lost (avoid false sign-outs)
+            if (_connectionSubscription != null && _isConnectionError(error)) {
+              onConnectionLost?.call();
+            } else {
+              _log.fine('Non-critical error during monitoring; ignoring.');
+            }
+          },

Add this helper inside the class (outside the selected range):

bool _isConnectionError(Object error) {
  final msg = error.toString().toLowerCase();
  // Tweak predicates to match your repo/RPC error surface
  return msg.contains('device not found') ||
         msg.contains('disconnected') ||
         msg.contains('unreachable') ||
         msg.contains('no such device');
}
packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (1)

208-221: Good: devicePubkey is now threaded through to the monitor.

This resolves the prior feedback about ignoring the devicePubkey parameter. Consider populating devicePubkey from the authenticated device context when available to ensure precise tracking if multiple devices can be connected.

If the repository exposes the active device's pubkey (e.g., via getConnectionStatus or a stored field after init), pass it here:

_startConnectionMonitoring(devicePubkey: activeDevicePubkey);

Please verify whether such a getter exists in TrezorRepository or the initialization result so the monitor can filter to the correct device.

🧹 Nitpick comments (8)
packages/komodo_defi_sdk/example/pubspec.yaml (2)

11-12: Consider using a git reference or version for the dragon_logs dependency.

The dragon_logs dependency uses a local path reference. If this package is intended for broader use or CI/CD pipelines, consider using a git reference or published version to ensure reproducibility and avoid path resolution issues in different environments.


31-31: Consider using a more flexible logging version constraint.

The logging dependency is pinned to exactly version 1.3.0. Consider using a version constraint like ^1.3.0 to allow patch updates while maintaining compatibility.

-  logging: ^1.3.0
+  logging: ^1.3.0
packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (1)

225-229: Consider yielding a disconnected status on initial failure instead of throwing.

The current implementation throws an exception if the initial status check fails. For consistency with the polling loop error handling (which yields disconnected), consider yielding a disconnected status instead.

    try {
      last = await getConnectionStatus(devicePubkey: devicePubkey);
      yield last;
    } catch (e) {
-     // If initial status check fails, we can't proceed
-     throw TrezorException(
-       'Failed to get initial connection status',
-       e.toString(),
-     );
+     // If initial status check fails, treat as disconnected
+     yield TrezorConnectionStatus.disconnected;
+     return;
    }
packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart (2)

29-31: Monitoring timeout (30m) risks leaving users signed in but unmonitored; prefer indefinite or explicit auto-restart.

After maxDuration elapses, onDone fires and monitoring stops with only a log line. If the user remains signed in, they won't be auto-signed out on later disconnections. Recommend one of:

  • Make monitoring default indefinite (preferred), or
  • Auto-restart monitoring onDone, or
  • Treat unexpected onDone as connection loss and sign the user out.

Optional diffs to consider:

  1. Extend the default duration to a safer window (e.g., 24h):
-    Duration maxDuration = const Duration(minutes: 30),
+    Duration maxDuration = const Duration(hours: 24),
  1. Auto-restart when the stream ends unexpectedly:
-          onDone: () {
-            _log.info('Trezor connection monitoring stopped');
-          },
+          onDone: () {
+            _log.info('Trezor connection monitoring stopped');
+            // Optional: auto-restart to avoid leaving user unmonitored
+            _log.fine('Auto-restarting Trezor connection monitoring');
+            startMonitoring(
+              devicePubkey: devicePubkey,
+              pollInterval: pollInterval,
+              maxDuration: maxDuration,
+              onConnectionLost: onConnectionLost,
+              onConnectionRestored: onConnectionRestored,
+              onStatusChanged: onStatusChanged,
+            );
+          },

If the repository deliberately completes the stream (e.g., maintenance), confirm whether onDone should sign out the user instead. If you prefer indefinite monitoring, we can remove maxDuration entirely assuming repository supports it.

Also applies to: 73-76


80-87: Await subscription cancellation to avoid racey onError/onDone after stop.

stopMonitoring currently ignores the Future returned by cancel(). Making it async and awaiting cancellation improves determinism and prevents post-stop events from racing with cleanup.

Apply this diff:

-  /// Stop monitoring the Trezor connection status.
-  void stopMonitoring() {
-    if (_connectionSubscription != null) {
-      _log.info('Stopping Trezor connection monitoring');
-      _connectionSubscription?.cancel();
-      _connectionSubscription = null;
-      _lastStatus = null;
-    }
-  }
+  /// Stop monitoring the Trezor connection status.
+  Future<void> stopMonitoring() async {
+    if (_connectionSubscription != null) {
+      _log.info('Stopping Trezor connection monitoring');
+      await _connectionSubscription?.cancel();
+      _connectionSubscription = null;
+      _lastStatus = null;
+    }
+  }

Note: This change requires awaiting stopMonitoring() at call sites (see suggestions in TrezorAuthService).

packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (3)

111-114: Stop monitoring before sign-out is correct; consider awaiting if stop becomes async.

The ordering is right. If you adopt the async stopMonitoring from the monitor, update this to await the stop.

-  Future<void> signOut() async {
-    _stopConnectionMonitoring();
-    await _authService.signOut();
-  }
+  Future<void> signOut() async {
+    await _stopConnectionMonitoring();
+    await _authService.signOut();
+  }

223-228: Make _stopConnectionMonitoring async to await underlying cancellation.

If you adopt the async stop in the monitor, mirror it here to ensure proper sequencing during teardown.

-  /// Stop monitoring Trezor connection status.
-  void _stopConnectionMonitoring() {
-    if (_connectionMonitor.isMonitoring) {
-      _connectionMonitor.stopMonitoring();
-    }
-  }
+  /// Stop monitoring Trezor connection status.
+  Future<void> _stopConnectionMonitoring() async {
+    if (_connectionMonitor.isMonitoring) {
+      await _connectionMonitor.stopMonitoring();
+    }
+  }

230-241: Optional: move _stopConnectionMonitoring() outside try/catch to avoid swallowing unexpected failures.

Unlikely to throw, but placing it outside the try keeps the catch focused on sign-out errors.

-      try {
-        _stopConnectionMonitoring();
-        await _authService.signOut();
-      } catch (_) {
+      _stopConnectionMonitoring();
+      try {
+        await _authService.signOut();
+      } catch (_) {
         // ignore sign out errors
       }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32c0006 and 4b1f5fd.

⛔ Files ignored due to path filters (1)
  • packages/komodo_defi_sdk/example/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (7 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_status.dart (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (2 hunks)
  • packages/komodo_defi_rpc_methods/lib/src/rpc_methods/trezor/trezor_rpc_namespace.dart (4 hunks)
  • packages/komodo_defi_sdk/example/lib/blocs/auth/auth_bloc.dart (1 hunks)
  • packages/komodo_defi_sdk/example/lib/blocs/auth/trezor_auth_mixin.dart (9 hunks)
  • packages/komodo_defi_sdk/example/pubspec.yaml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_status.dart
⏰ 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). (1)
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (18)
packages/komodo_defi_sdk/example/pubspec.yaml (2)

19-20: LGTM! The komodo_defi_rpc_methods dependency is correctly configured.

The new dependency enables the Trezor RPC functionality introduced in this PR.


39-40: LGTM! The integration_test dependency reordering is appropriate.

The dependency was reordered but remains unchanged in functionality.

packages/komodo_defi_rpc_methods/lib/src/rpc_methods/trezor/trezor_rpc_namespace.dart (3)

3-4: LGTM! Import statement correctly updated to use shared types.

The types have been properly migrated to the shared types package, promoting better code organization and reusability.


111-121: LGTM! Well-documented connection status method.

The new connectionStatus method is properly implemented and follows the established patterns in the codebase.


210-227: LGTM! Request class properly structured.

The TrezorConnectionStatusRequest class follows the established request pattern with appropriate optional parameter handling.

packages/komodo_defi_sdk/example/lib/blocs/auth/auth_bloc.dart (2)

9-9: LGTM! Logging import added for enhanced debugging.

The logging package import enables better debugging and monitoring of the authentication flow.


14-14: LGTM! Part directive reordering is appropriate.

The reordering places the mixin after the event definitions, which is a logical organization.

packages/komodo_defi_sdk/example/lib/blocs/auth/trezor_auth_mixin.dart (4)

7-7: LGTM! Logger instance properly configured.

The static logger follows best practices with an appropriate name for identification.


15-20: LGTM! Event handler registration with appropriate logging.

The setup method properly logs the registration of event handlers and includes the new cancellation handler.


68-69: LGTM! Improved error handling with stack trace logging.

Capturing and logging the stack trace will help with debugging production issues.


187-195: LGTM! Cancellation handler properly implemented.

The new cancellation handler correctly logs the event and transitions to the unauthenticated state.

packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (2)

193-198: LGTM! Connection status method properly implemented.

The method correctly delegates to the RPC client and follows the established pattern.


200-206: LGTM! Status parsing method is well-structured.

The method properly converts the raw response to the enum type.

packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (5)

19-21: Constructor wiring of TrezorConnectionMonitor looks correct.

Using the repository param to initialize the monitor in the initializer list is sound and keeps responsibilities separated.


105-108: Dispose sequencing LGTM.

Disposing the connection monitor before the composed auth service is the right order and avoids dangling callbacks.


136-141: Starting monitoring after password-based init is appropriate for this non-streamed path.

This addresses the earlier concern about duplicate starts: signIn here uses _initializeTrezorWithPassphrase (not the streamed path), so starting monitoring here is necessary and not redundant with _authenticateTrezorStream.


168-173: Same as above: non-stream register path correctly starts monitoring post-auth.

No duplication with stream path; this is the required spot for the imperative path.


328-328: Stream path startMonitoring is correct; ensure you don't accidentally start twice.

Given the structure, this path is mutually exclusive with the imperative sign-in/register paths, so no double-start occurs. Keep it this way to avoid duplicate subscriptions.

@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 12, 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.

@takenagain takenagain requested a review from Copilot August 12, 2025 18:22
Copy link
Copy Markdown
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 adds real-time Trezor connection monitoring with automatic sign-out functionality when the device becomes disconnected. It introduces connection status polling, new data models for Trezor operations, and a polling utility for robust background operations.

Key changes:

  • Implements Trezor connection status monitoring with automatic sign-out on disconnect
  • Adds new data models for TrezorDeviceInfo and TrezorUserActionData with proper validation
  • Introduces a generic polling utility with configurable backoff strategies and error handling

Reviewed Changes

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

Show a summary per file
File Description
packages/komodo_defi_types/lib/src/utils/poll_utils.dart New polling utility with timeout, backoff, and error handling
packages/komodo_defi_types/test/utils/poll_utils_test.dart Comprehensive test suite for the polling utility
packages/komodo_defi_types/lib/src/trezor/ New data models for Trezor device info and user actions
packages/komodo_defi_local_auth/lib/src/trezor/ Connection monitoring service and repository enhancements
packages/komodo_defi_rpc_methods/lib/src/rpc_methods/trezor/ RPC method updates for connection status queries
Comments suppressed due to low confidence (1)

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

Comment thread packages/komodo_defi_types/lib/src/trezor/trezor_user_action_data.dart Outdated
Comment thread packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart Outdated
Comment thread packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart Outdated
cursor[bot]

This comment was marked as outdated.

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: 0

♻️ Duplicate comments (6)
packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (2)

217-227: Error handling for initial status check is appropriate.

The method properly handles initial connection failures by yielding disconnected status and terminating the stream.


229-247: Consider documenting the timeout behavior more clearly.

The behavior when maxDuration expires (emitting unreachable status) should be documented to clarify that this doesn't necessarily mean the device is disconnected, just that monitoring has timed out.

Consider adding a comment to clarify the timeout behavior:

   if (maxDuration != null && stopwatch!.elapsed >= maxDuration) {
+    // Emit unreachable to indicate monitoring timeout, not actual disconnection
     yield TrezorConnectionStatus.unreachable;
   }
packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (4)

241-252: Potential circular dependency issue.

The _stopConnectionMonitoring() call inside _signOutCurrentTrezorUser() could create unexpected behavior since this method is also called from the connection monitor's onConnectionLost callback (line 225).

Consider checking if monitoring is active before stopping to avoid potential issues:

 Future<void> _signOutCurrentTrezorUser() async {
   final current = await _authService.getActiveUser();
   if (current?.walletId.name == trezorWalletName) {
     _log.warning("Signing out current '${current?.walletId.name}' user");
-    await _stopConnectionMonitoring();
+    if (_connectionMonitor.isMonitoring) {
+      await _stopConnectionMonitoring();
+    }
     try {
       await _authService.signOut();
     } catch (_) {
       // ignore sign out errors
     }
   }
 }

147-151: Connection monitoring is redundantly started.

The connection monitoring is started here and also in _authenticateTrezorStream (line 338). Since _initializeTrezorWithPassphrase internally uses _initializeTrezorAndAuthenticate, which yields states processed elsewhere, the monitoring here appears redundant.


179-183: Connection monitoring is redundantly started.

Similar to the signIn method, connection monitoring is started here and also in _authenticateTrezorStream.


220-231: Use the devicePubkey parameter.

The devicePubkey parameter is accepted but not used when starting monitoring.

🧹 Nitpick comments (1)
packages/komodo_defi_local_auth/test/src/trezor/trezor_connection_monitor_test.dart (1)

198-217: Consider verifying the error handling behavior more thoroughly.

The test verifies that onConnectionLost is called when an error occurs, but it might be worth also verifying that the monitoring continues after the error (unless explicitly stopped).

Consider extending the test to verify post-error behavior:

 test('onError triggers onConnectionLost while monitoring', () async {
   final repo = _TestTrezorRepository();
   final monitor = TrezorConnectionMonitor(repo);

   var lost = 0;
-  monitor.startMonitoring(onConnectionLost: () => lost++);
+  var statusCount = 0;
+  monitor.startMonitoring(
+    onConnectionLost: () => lost++,
+    onStatusChanged: (_) => statusCount++,
+  );

   // Emit any status to set previousStatus
   repo.emit(TrezorConnectionStatus.connected);
   await Future<void>.delayed(const Duration(milliseconds: 5));
+  expect(statusCount, 1);

   // Now emit error from repository stream
   repo.emitError(Exception('stream failure'));
   await Future<void>.delayed(const Duration(milliseconds: 5));

   expect(lost, 1);
+  
+  // Verify monitoring continues after error if not stopped
+  repo.emit(TrezorConnectionStatus.busy);
+  await Future<void>.delayed(const Duration(milliseconds: 5));
+  expect(statusCount, 2);

   await monitor.stopMonitoring();
   await repo.close();
 });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b1f5fd and a8ca5e0.

📒 Files selected for processing (7)
  • packages/komodo_defi_local_auth/.gitignore (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (7 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart (1 hunks)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (5 hunks)
  • packages/komodo_defi_local_auth/test/src/trezor/trezor_auth_service_test.dart (1 hunks)
  • packages/komodo_defi_local_auth/test/src/trezor/trezor_connection_monitor_test.dart (1 hunks)
  • packages/komodo_defi_local_auth/test/src/trezor/trezor_repository_test.dart (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/komodo_defi_local_auth/.gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/komodo_defi_local_auth/lib/src/trezor/trezor_connection_monitor.dart
⏰ 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). (3)
  • GitHub Check: build_and_preview_playground_preview
  • GitHub Check: build_and_preview_sdk_example_preview
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (54)
packages/komodo_defi_local_auth/test/src/trezor/trezor_connection_monitor_test.dart (13)

1-11: LGTM!

The imports and test setup are properly structured.


8-11: LGTM!

Clean implementation of the dummy API client for test isolation.


13-51: LGTM!

Well-designed test double that provides control over stream emissions for testing the TrezorConnectionMonitor behavior.


55-82: LGTM!

Comprehensive test that verifies status emissions, lastKnownStatus tracking, and monitoring state management.


84-120: LGTM!

Excellent test that validates the nuanced connection loss/restoration callback behavior across different status transitions.


122-147: LGTM!

Good test coverage for the onConnectionRestored callback, ensuring it only triggers on unavailable-to-available transitions.


149-172: LGTM!

Validates that monitoring parameters are correctly forwarded to the repository.


174-196: LGTM!

Important test that verifies proper cleanup behavior when monitoring is stopped.


219-244: LGTM!

Verifies that starting a new monitoring session properly replaces the previous one.


246-256: LGTM!

Simple but essential test for dispose behavior.


258-281: LGTM!

Good test that verifies monitoring state is properly updated when the underlying stream completes.


283-301: LGTM!

Validates that errors after stopping monitoring are properly ignored.


303-330: LGTM!

Important edge case test that verifies no spurious callbacks occur when monitoring is started and stopped without any events.

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

1-11: LGTM!

The imports are properly organized and include all necessary dependencies for testing.


12-15: LGTM!

Clean implementation of the dummy API client for test isolation.


17-56: LGTM!

Well-designed fake repository that provides control over initialization events and tracks method invocations for test assertions.


58-97: LGTM!

Good fake implementation of TrezorConnectionMonitor that tracks monitoring state and method calls.


99-201: LGTM!

Comprehensive fake implementation of IAuthService that provides necessary functionality for testing TrezorAuthService behavior.


205-230: LGTM!

Good test that validates the service correctly rejects non-Trezor authentication options.


232-257: LGTM!

Validates that register method also properly rejects non-Trezor authentication options.


259-346: LGTM!

Comprehensive test that validates the complete sign-in flow including wallet registration, password generation and storage, passphrase forwarding, and monitoring startup.


348-404: LGTM!

Good test coverage for the streaming sign-in path, verifying state emissions and monitor activation.


406-442: LGTM!

Important test that verifies proper error handling and cleanup during sign-in failures.


444-488: LGTM!

Good edge case test that validates proper error handling when a stored password is missing for an existing user.


490-512: LGTM!

Simple but important test for password cleanup functionality.


514-535: LGTM!

Validates that sign-out properly stops monitoring and delegates to the underlying auth service.

packages/komodo_defi_local_auth/lib/src/trezor/trezor_repository.dart (5)

51-54: Good improvement to timer management.

The addition of Timer variable and comment clearly indicates the intent to prevent timer leaks when streams are cancelled by subscribers.


119-125: LGTM! Prevents race conditions.

Good change to avoid immediate polling and potential race conditions with KDF task creation. Using the polling interval for the first status check is a sensible approach.


128-134: Error handling improvement.

The change from throwing a TrezorException to yielding an error state provides better error handling consistency with the stream-based API.


135-144: Excellent timer cleanup logic.

The finally block ensures the timer is always cancelled, preventing memory leaks even if the stream is cancelled by the subscriber or exits early.


194-202: LGTM!

Clean implementation of getConnectionStatus that properly fetches and parses the connection status.

packages/komodo_defi_local_auth/lib/src/trezor/trezor_auth_service.dart (5)

19-29: Good dependency injection design.

The constructor now properly accepts optional dependencies with sensible defaults, improving testability and flexibility.


115-118: Proper lifecycle management.

The dispose method correctly disposes the connection monitor before the auth service.


121-124: LGTM!

The signOut method properly stops monitoring before signing out.


234-238: LGTM!

Clean helper method for stopping monitoring with proper state checking.


337-339: LGTM!

Properly starts monitoring after successful authentication in the streaming flow.

packages/komodo_defi_local_auth/test/src/trezor/trezor_repository_test.dart (18)

1-11: LGTM!

The imports are properly organized with appropriate test utilities.


13-48: Well-designed fake API client.

The FakeApiClient provides excellent control over RPC responses for testing, with proper request tracking and error handling.


50-91: LGTM!

Clean helper functions for creating API response structures.


94-174: Comprehensive initialization test.

Excellent test that verifies the complete initialization flow including status mapping and device info extraction.


176-210: LGTM!

Good test for error handling when status returns an error response.


212-245: LGTM!

Important test that verifies stream error handling when the status call throws an exception.


248-280: LGTM!

Good input validation tests for PIN and passphrase methods.


282-320: LGTM!

Validates cancellation behavior including state emission and proper cleanup.


322-350: LGTM!

Good test coverage for connection status enum mapping.


352-396: LGTM!

Excellent test that verifies status change detection and stream termination on disconnect.


398-443: LGTM!

Important test that verifies polling stops when the listener cancels the subscription.


445-495: LGTM!

Validates that polling stops after receiving a disconnected status.


497-527: LGTM!

Verifies the timeout behavior that emits unreachable status after maxDuration.


529-558: LGTM!

Good test for error handling during polling that properly emits disconnected status.


561-596: LGTM!

Validates that dispose properly cancels active initializations.


599-639: LGTM!

Good test that verifies null maxDuration behavior continues polling until disconnected.


640-676: LGTM!

Validates that no immediate polling occurs with long intervals, preventing unnecessary status checks.


678-731: LGTM!

Excellent test that ensures timers are properly cancelled when streams are cancelled, preventing resource leaks.

@takenagain takenagain requested a review from CharlVS August 12, 2025 18:44
cursor[bot]

This comment was marked as outdated.

freezed by default adds all fields to toString overrides, which could result in user pin/passphrases being printed to logs
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

…dk-flutter into feat/trezor-connection-status

# Conflicts:
#	packages/komodo_defi_sdk/example/pubspec.yaml
Rename the dragon charts folder to be consistent with the package name.

NO FUNCTIONAL CHANGES
@CharlVS CharlVS merged commit a2c278e into dev Aug 13, 2025
4 checks passed
@CharlVS CharlVS deleted the feat/trezor-connection-status branch August 13, 2025 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants