mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Add thread-safety and BLE support for Ledger and Trezor devices (#3638)
* feat: support BLE device detection for Ledger and Trezor wallets, update trezor-flutter dependency * feat: add BLE connection state listener for Trezor devices, handle disconnect events, and clean up resources on close * feat: add mutex locking to MoneroTrezorService for thread-safe operations
This commit is contained in:
@@ -58,7 +58,7 @@ dependencies:
|
||||
trezor_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/trezor-flutter
|
||||
ref: 02771769fc800c06e29ac9186e37e9c2aeb0b54c
|
||||
ref: 591d4b8c821b9c10561f848b866324a9a8dcb489
|
||||
path: trezor-flutter
|
||||
bitbox_flutter:
|
||||
path: ../scripts/bitbox_flutter
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import "dart:convert";
|
||||
|
||||
import "package:cw_core/hardware/hardware_wallet_service.dart";
|
||||
import "package:mutex/mutex.dart";
|
||||
import "package:trezor_flutter/trezor_flutter.dart";
|
||||
|
||||
class MoneroTrezorService extends HardwareWalletService {
|
||||
MoneroTrezorService(this.client);
|
||||
|
||||
final TrezorClient client;
|
||||
|
||||
static final Mutex _mutex = Mutex();
|
||||
|
||||
static Future<T> runBlocking<T>(Future<T> Function() operation) => _mutex.protect(operation);
|
||||
}
|
||||
|
||||
class MoneroTrezorWatchCredentials {
|
||||
@@ -22,7 +27,7 @@ class Trezor {
|
||||
final MoneroTrezorService service;
|
||||
|
||||
Future<MoneroTrezorWatchCredentials> getWatchCredentials() async {
|
||||
final credentials = await TrezorMonero(service.client).getWatchCredentials();
|
||||
final credentials = await MoneroTrezorService.runBlocking(TrezorMonero(service.client).getWatchCredentials);
|
||||
|
||||
return MoneroTrezorWatchCredentials(credentials.$1, credentials.$2);
|
||||
}
|
||||
@@ -45,11 +50,15 @@ class Trezor {
|
||||
),
|
||||
);
|
||||
}
|
||||
final keyImages = await TrezorMonero(service.client).syncKeyImages(txIds);
|
||||
final keyImages = await MoneroTrezorService.runBlocking(
|
||||
() => TrezorMonero(service.client).syncKeyImages(txIds),
|
||||
);
|
||||
|
||||
return jsonEncode(keyImages.toMap());
|
||||
}
|
||||
|
||||
Future<String> signTransaction(String json) =>
|
||||
TrezorMonero(service.client).signTransaction(jsonDecode(json) as Map<String, dynamic>);
|
||||
Future<String> signTransaction(String json) => MoneroTrezorService.runBlocking(
|
||||
() =>
|
||||
TrezorMonero(service.client).signTransaction(jsonDecode(json) as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ dependencies:
|
||||
trezor_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/trezor-flutter.git
|
||||
ref: 02771769fc800c06e29ac9186e37e9c2aeb0b54c
|
||||
ref: 591d4b8c821b9c10561f848b866324a9a8dcb489
|
||||
path: trezor-flutter
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
@@ -108,6 +108,8 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_loadConnectedDevices();
|
||||
|
||||
_bleStateTimer = Timer.periodic(
|
||||
const Duration(seconds: 1),
|
||||
(_) => widget.hardwareWalletVM.updateBleState(),
|
||||
@@ -131,6 +133,23 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadConnectedDevices() async {
|
||||
try {
|
||||
final connected = await widget.hardwareWalletVM.getConnectedBleDevices();
|
||||
|
||||
printV(connected);
|
||||
if (!mounted || connected.isEmpty) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
bleDevices.addAll(connected);
|
||||
longWait = false;
|
||||
});
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_bleRefreshTimer?.cancel();
|
||||
|
||||
@@ -18,6 +18,8 @@ abstract class HardwareWalletViewModel {
|
||||
|
||||
Future<List<HardwareWalletDevice>> getAllUsbDevices();
|
||||
|
||||
Future<List<HardwareWalletDevice>> getConnectedBleDevices() async => [];
|
||||
|
||||
Future<void> stopScanning();
|
||||
|
||||
Future<bool> connectDevice(HardwareWalletDevice device, WalletType type);
|
||||
|
||||
@@ -120,6 +120,14 @@ abstract class LedgerViewModelBase extends HardwareWalletViewModel with Store {
|
||||
Future<List<HardwareWalletDevice>> getAllUsbDevices() =>
|
||||
ledgerPlusUSB.devices.then((devices) => devices.map(LedgerHardwareWalletDevice.new).toList());
|
||||
|
||||
@override
|
||||
Future<List<HardwareWalletDevice>> getConnectedBleDevices() async {
|
||||
if (!_bleIsInitialized) {
|
||||
return const [];
|
||||
}
|
||||
return (await ledgerPlusBLE.devices).map(LedgerHardwareWalletDevice.new).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stopScanning() async {
|
||||
if (_bleIsInitialized) {
|
||||
|
||||
@@ -48,6 +48,7 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
}
|
||||
}
|
||||
|
||||
StreamSubscription<sdk.BleConnectionState>? _connectionChangeSubscription;
|
||||
final connect_sdk.TrezorConnect trezorConnect;
|
||||
final SecureStorage _secureStorage;
|
||||
|
||||
@@ -125,6 +126,14 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
Future<List<HardwareWalletDevice>> getAllUsbDevices() =>
|
||||
trezorUSB.devices.then((devices) => devices.map(TrezorHardwareWalletDevice.new).toList());
|
||||
|
||||
@override
|
||||
Future<List<HardwareWalletDevice>> getConnectedBleDevices() async {
|
||||
if (!_bleIsInitialized) {
|
||||
return const [];
|
||||
}
|
||||
return (await trezorBLE.devices).map(TrezorHardwareWalletDevice.new).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stopScanning() async {
|
||||
if (_bleIsInitialized) {
|
||||
@@ -168,6 +177,9 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
device.connectionType == HardwareWalletConnectionType.ble ? trezorBLE : trezorUSB;
|
||||
final connection = await trezorInterface.connect(device.device);
|
||||
|
||||
_connectionChangeSubscription ??=
|
||||
trezorInterface.deviceStateChanges.listen(_connectionChangeListener);
|
||||
|
||||
if (!isRetry) {
|
||||
unawaited(
|
||||
showModalBottomSheet(
|
||||
@@ -342,6 +354,13 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
}
|
||||
}
|
||||
|
||||
void _connectionChangeListener(sdk.BleConnectionState event) {
|
||||
printV("Ledger Device State Changed: $event");
|
||||
if (event == sdk.BleConnectionState.disconnected && !isConnecting) {
|
||||
_client = null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> syncKeyImages(WalletBase wallet) async {
|
||||
if (wallet.type == WalletType.monero) {
|
||||
try {
|
||||
@@ -352,6 +371,17 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
try {
|
||||
await _connectionChangeSubscription?.cancel();
|
||||
|
||||
_connectionChangeSubscription = null;
|
||||
isConnecting = false;
|
||||
await stopScanning();
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TrezorParingState {
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ dependencies:
|
||||
trezor_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/trezor-flutter.git
|
||||
ref: 02771769fc800c06e29ac9186e37e9c2aeb0b54c
|
||||
ref: 591d4b8c821b9c10561f848b866324a9a8dcb489
|
||||
path: trezor-flutter
|
||||
bitbox_flutter:
|
||||
path: ./scripts/bitbox_flutter
|
||||
|
||||
@@ -1481,12 +1481,12 @@ dependency_overrides:
|
||||
trezor_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/trezor-flutter.git
|
||||
ref: 02771769fc800c06e29ac9186e37e9c2aeb0b54c
|
||||
ref: 591d4b8c821b9c10561f848b866324a9a8dcb489
|
||||
path: ./trezor-flutter
|
||||
trezor_usb_transport:
|
||||
git:
|
||||
url: https://github.com/cake-tech/trezor-flutter.git
|
||||
ref: 02771769fc800c06e29ac9186e37e9c2aeb0b54c
|
||||
ref: 591d4b8c821b9c10561f848b866324a9a8dcb489
|
||||
path: ./trezor_usb_transport
|
||||
tuple:
|
||||
git:
|
||||
|
||||
Reference in New Issue
Block a user