Skip to content

Commit ea65e77

Browse files
refactor(ledger): align the failure family with the #1895 standard
Four points where the ledger implementation drifted from the standard in #2293: The failure family moves to domain/ and the exception family to data/, matching the layer each word belongs to — a Failure is a domain value, an Exception is thrown infra. The catch-all now returns the shared oopsSomethingWentWrong instead of a ledger-specific "unknown error" string, so the redundant key is gone from all 27 locales. ConnectionTypeNotInitialized no longer maps to the generic failure. The transports are nullable and initialized during scan, so this fires on a reachable path and means "no connection available" — which is actionable, unlike "Oops, something went wrong". The APDU status word is only read when it is labelled (0x6985, sw=6985). The previous pattern matched any four hex-ish characters, so "timeout after 6985 ms" was reported to the user as "you rejected the operation on the device". Also drops the last `dynamic` from the operation seam and closes the repository contract with `abstract interface class`.
1 parent 2648915 commit ea65e77

44 files changed

Lines changed: 99 additions & 103 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

lib/core/ledger/data/datasources/ledger_device_datasource.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import 'dart:io';
44
import 'package:bb_mobile/core/entities/signer_device_entity.dart';
55
import 'package:bb_mobile/core/ledger/data/models/ledger_device_model.dart';
66
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
7-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_exception.dart';
7+
import 'package:bb_mobile/core/ledger/data/ledger_exception.dart';
88
import 'package:bb_mobile/core/utils/logger.dart';
99
import 'package:bb_mobile/core/wallet/domain/entities/wallet.dart';
1010
import 'package:bull_sdk/bdk.dart' as bdk;
File renamed without changes.

lib/core/ledger/data/repositories/ledger_device_repository_impl.dart

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import 'package:bb_mobile/core/entities/signer_device_entity.dart';
22
import 'package:bb_mobile/core/ledger/data/datasources/ledger_device_datasource.dart';
33
import 'package:bb_mobile/core/ledger/data/models/ledger_device_model.dart';
44
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
5-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_exception.dart';
6-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_failure.dart';
5+
import 'package:bb_mobile/core/ledger/data/ledger_exception.dart';
6+
import 'package:bb_mobile/core/ledger/domain/ledger_failure.dart';
77
import 'package:bb_mobile/core/ledger/domain/repositories/ledger_device_repository.dart';
88
import 'package:bb_mobile/core/utils/logger.dart';
99
import 'package:bb_mobile/core/utils/result.dart';
@@ -128,9 +128,12 @@ class LedgerDeviceRepositoryImpl implements LedgerDeviceRepository {
128128
} on InvalidMagicBytesLedgerException {
129129
return const Err(LedgerInvalidPsbtFailure());
130130
} on ConnectionTypeNotInitializedLedgerException {
131-
// Internal wiring bug — never a meaningful message for the user.
131+
// The transport for this device was never initialized (its scan did not
132+
// run or did not complete), so there is nothing to talk to. That is the
133+
// same situation as a missing connection from the user's point of view —
134+
// and "no connection available" is actionable, unlike a generic "oops".
132135
return const Err(
133-
LedgerUnexpectedFailure('connection type not initialized'),
136+
LedgerNoConnectionFailure('connection type not initialized'),
134137
);
135138
} catch (e, st) {
136139
final failure = _interpretRawError(e);
@@ -171,16 +174,22 @@ class LedgerDeviceRepositoryImpl implements LedgerDeviceRepository {
171174
);
172175

173176
/// Extracts a normalized (lowercase, no `0x`) 4-hex-digit APDU status word.
174-
/// Matches are anchored on word boundaries and accept an optional `0x`
175-
/// prefix, so a status word survives but an incidental 4-hex run inside a
176-
/// txid/address does not get mistaken for one.
177177
String? _extractApduCode(String error) {
178178
final match = _apduCodePattern.firstMatch(error);
179-
return match?.group(1)?.toLowerCase();
179+
if (match == null) return null;
180+
return (match.group(1) ?? match.group(2))?.toLowerCase();
180181
}
181182

183+
/// Matches an APDU status word only when it is unambiguously labelled: either
184+
/// hex-prefixed (`0x6985`) or introduced by a status-word keyword (`sw=6985`,
185+
/// `status word 6985`, `apdu: 6985`). A bare 4-character run is deliberately
186+
/// NOT matched — `timeout after 6985 ms`, or an incidental slice of a txid,
187+
/// would otherwise be read as "rejected by user" and show the user a
188+
/// confidently wrong reason.
182189
static final RegExp _apduCodePattern = RegExp(
183-
r'\b(?:0x)?([0-9a-f]{4})\b',
190+
r'0x([0-9a-f]{4})\b'
191+
r'|\b(?:sw|status(?:\s*word)?|apdu(?:\s*(?:code|status))?|code)'
192+
r'\s*[:=]?\s*(?:0x)?([0-9a-f]{4})\b',
184193
caseSensitive: false,
185194
);
186195
}

lib/core/ledger/domain/errors/ledger_failure.dart renamed to lib/core/ledger/domain/ledger_failure.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
import 'package:bb_mobile/core/failures/failure.dart';
22

3-
/// Closed set of every failure the ledger domain surfaces to the user.
4-
/// `sealed` keeps it closed (exhaustive switches; no foreign variants). Pure
5-
/// Dart — the user-facing message lives in the presentation extension
6-
/// `ledger_failure_l10n.dart`, never here. The raw device/SDK reason is logged
7-
/// at the repository boundary and, when kept at all, lives only in
8-
/// [Failure.logMessage] for logs/Sentry.
93
sealed class LedgerFailure extends Failure {
104
const LedgerFailure([super.logMessage]);
115
}

lib/core/ledger/domain/repositories/ledger_device_repository.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import 'package:bb_mobile/core/entities/signer_device_entity.dart';
22
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
3-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_failure.dart';
3+
import 'package:bb_mobile/core/ledger/domain/ledger_failure.dart';
44
import 'package:bb_mobile/core/utils/result.dart';
55
import 'package:bb_mobile/core/wallet/domain/entities/wallet.dart';
66
import 'package:meta/meta.dart';
77

8-
abstract class LedgerDeviceRepository {
8+
abstract interface class LedgerDeviceRepository {
99
@useResult
1010
Future<Result<List<LedgerDeviceEntity>, LedgerFailure>> scanDevices({
1111
SignerDeviceEntity? deviceType,

lib/core/ledger/domain/usecases/connect_ledger_device_usecase.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
2-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_failure.dart';
2+
import 'package:bb_mobile/core/ledger/domain/ledger_failure.dart';
33
import 'package:bb_mobile/core/ledger/domain/repositories/ledger_device_repository.dart';
44
import 'package:bb_mobile/core/utils/result.dart';
55
import 'package:meta/meta.dart';

lib/core/ledger/domain/usecases/get_ledger_watch_only_wallet_usecase.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:bb_mobile/core/entities/signer_entity.dart';
22
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
3-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_failure.dart';
3+
import 'package:bb_mobile/core/ledger/domain/ledger_failure.dart';
44
import 'package:bb_mobile/core/ledger/domain/repositories/ledger_device_repository.dart';
55
import 'package:bb_mobile/core/settings/data/settings_repository.dart';
66
import 'package:bb_mobile/core/utils/result.dart';

lib/core/ledger/domain/usecases/scan_ledger_devices_usecase.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:bb_mobile/core/entities/signer_device_entity.dart';
22
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
3-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_failure.dart';
3+
import 'package:bb_mobile/core/ledger/domain/ledger_failure.dart';
44
import 'package:bb_mobile/core/ledger/domain/repositories/ledger_device_repository.dart';
55
import 'package:bb_mobile/core/utils/result.dart';
66
import 'package:meta/meta.dart';

lib/core/ledger/domain/usecases/sign_psbt_ledger_usecase.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
2-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_failure.dart';
2+
import 'package:bb_mobile/core/ledger/domain/ledger_failure.dart';
33
import 'package:bb_mobile/core/ledger/domain/repositories/ledger_device_repository.dart';
44
import 'package:bb_mobile/core/utils/result.dart';
55
import 'package:bb_mobile/core/wallet/domain/entities/wallet.dart';

lib/core/ledger/domain/usecases/verify_address_ledger_usecase.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:bb_mobile/core/ledger/domain/entities/ledger_device_entity.dart';
2-
import 'package:bb_mobile/core/ledger/domain/errors/ledger_failure.dart';
2+
import 'package:bb_mobile/core/ledger/domain/ledger_failure.dart';
33
import 'package:bb_mobile/core/ledger/domain/repositories/ledger_device_repository.dart';
44
import 'package:bb_mobile/core/utils/result.dart';
55
import 'package:bb_mobile/core/wallet/domain/entities/wallet.dart';

0 commit comments

Comments
 (0)