Generic fixes (#1454)

* Handle Bluetooth is disabled * Allow signMessage using ledger_bitcoin * Fix desktop wallet selection dropdown

Konstantin Ullrich committed May 17, 2024 at 08:15 UTC 82391d4a5b1b96961d43ed17a3b4853e8062f219
5 files changed +77 -44
cw_bitcoin/lib/bitcoin_wallet.dart
+30 -10
@@ -1,23 +1,24 @@
1 +import 'dart:convert';
2 +
3 +import 'package:bip39/bip39.dart' as bip39;
4 import 'package:bitcoin_base/bitcoin_base.dart';
5 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
6 import 'package:convert/convert.dart';
3 -
7 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
8 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
9 +import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
10 +import 'package:cw_bitcoin/electrum_balance.dart';
11 +import 'package:cw_bitcoin/electrum_wallet.dart';
12 +import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
13 import 'package:cw_bitcoin/psbt_transaction_builder.dart';
14 import 'package:cw_core/crypto_currency.dart';
15 import 'package:cw_core/unspent_coins_info.dart';
16 +import 'package:cw_core/wallet_info.dart';
17 +import 'package:flutter/foundation.dart';
18 import 'package:hive/hive.dart';
19 import 'package:ledger_bitcoin/ledger_bitcoin.dart';
20 import 'package:ledger_flutter/ledger_flutter.dart';
21 import 'package:mobx/mobx.dart';
12 -import 'package:flutter/foundation.dart';
13 -import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
14 -import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
15 -import 'package:cw_bitcoin/electrum_wallet.dart';
16 -import 'package:cw_core/wallet_info.dart';
17 -import 'package:cw_bitcoin/bitcoin_address_record.dart';
18 -import 'package:cw_bitcoin/electrum_balance.dart';
19 -import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
20 -import 'package:bip39/bip39.dart' as bip39;
22
23 part 'bitcoin_wallet.g.dart';
24
@@ -215,4 +216,23 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
216 final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
217 return BtcTransaction.fromRaw(hex.encode(rawHex));
218 }
219 +
220 + @override
221 + Future<String> signMessage(String message, {String? address = null}) async {
222 + if (walletInfo.isHardwareWallet) {
223 + final addressEntry = address != null
224 + ? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
225 + : null;
226 + final index = addressEntry?.index ?? 0;
227 + final isChange = addressEntry?.isHidden == true ? 1 : 0;
228 + final accountPath = walletInfo.derivationInfo?.derivationPath;
229 + final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
230 +
231 + final signature = await _bitcoinLedgerApp!
232 + .signMessage(_ledgerDevice!, message: ascii.encode(message), signDerivationPath: derivationPath);
233 + return base64Encode(signature);
234 + }
235 +
236 + return super.signMessage(message, address: address);
237 + }
238 }
cw_bitcoin/pubspec.lock
+3 -3
@@ -475,10 +475,10 @@ packages:
475 description:
476 path: "."
477 ref: HEAD
478 - resolved-ref: b6ed573cbeb57d5f0d39dfe4254bf9d15b620ab6
479 - url: "https://github.com/cake-tech/ledger-bitcoin.git"
478 + resolved-ref: f819d37e235e239c315e93856abbf5e5d3b71dab
479 + url: "https://github.com/cake-tech/ledger-bitcoin"
480 source: git
481 - version: "0.0.1"
481 + version: "0.0.2"
482 ledger_flutter:
483 dependency: "direct main"
484 description:
cw_bitcoin/pubspec.yaml
+1 -1
@@ -38,7 +38,7 @@ dependencies:
38 ledger_flutter: ^1.0.1
39 ledger_bitcoin:
40 git:
41 - url: https://github.com/cake-tech/ledger-bitcoin.git
41 + url: https://github.com/cake-tech/ledger-bitcoin
42
43 dev_dependencies:
44 flutter_test:
lib/src/screens/connect_device/connect_device_page.dart
+24 -14
@@ -3,6 +3,7 @@ import 'dart:io';
3
4 import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/src/screens/base_page.dart';
6 +// import 'package:cake_wallet/src/screens/connect_device/debug_device_page.dart';
7 import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
8 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
9 import 'package:cake_wallet/utils/responsive_layout_util.dart';
@@ -78,15 +79,13 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
79 @override
80 void initState() {
81 super.initState();
81 - Future.delayed(
82 - Duration(seconds: 1),
83 - () => _bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device))),
84 - );
85 - // _bleRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
82 + WidgetsBinding.instance.addPostFrameCallback((_) {
83 + _bleRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
84
87 - if (Platform.isAndroid) {
88 - _usbRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
89 - }
85 + if (Platform.isAndroid) {
86 + _usbRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
87 + }
88 + });
89 }
90
91 @override
@@ -103,14 +102,16 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
102 }
103
104 Future<void> _refreshBleDevices() async {
106 - final isBleEnabled = await Permission.bluetooth.serviceStatus.isEnabled;
107 -
108 - setState(() => bleIsEnabled = isBleEnabled);
109 -
110 - if (isBleEnabled) {
111 - _bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device)));
105 + try {
106 + _bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device)))
107 + ..onError((e) {
108 + throw e as Exception;
109 + });
110 + setState(() => bleIsEnabled = true);
111 _bleRefreshTimer?.cancel();
112 _bleRefreshTimer = null;
113 + } catch (e) {
114 + setState(() => bleIsEnabled = false);
115 }
116 }
117
@@ -142,6 +143,15 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
143 textAlign: TextAlign.center,
144 ),
145 ),
146 + // DeviceTile(
147 + // onPressed: () => Navigator.of(context).push(
148 + // MaterialPageRoute<void>(
149 + // builder: (BuildContext context) => DebugDevicePage(),
150 + // ),
151 + // ),
152 + // title: "Debug Ledger",
153 + // leading: imageLedger,
154 + // ),
155 if (!bleIsEnabled)
156 Padding(
157 padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart
+19 -16
@@ -117,22 +117,25 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
117 if (selectedWallet.isCurrent || !selectedWallet.isEnabled) {
118 return;
119 }
120 - final confirmed = await showPopUp<bool>(
121 - context: context,
122 - builder: (dialogContext) {
123 - return AlertWithTwoActions(
124 - alertTitle: S.of(context).change_wallet_alert_title,
125 - alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
126 - leftButtonText: S.of(context).cancel,
127 - rightButtonText: S.of(context).change,
128 - actionLeftButton: () => Navigator.of(dialogContext).pop(false),
129 - actionRightButton: () => Navigator.of(dialogContext).pop(true));
130 - }) ??
131 - false;
132 -
133 - if (confirmed) {
134 - await _loadWallet(selectedWallet);
135 - }
120 +
121 + WidgetsBinding.instance.addPostFrameCallback((_) async {
122 + final confirmed = await showPopUp<bool>(
123 + context: context,
124 + builder: (dialogContext) {
125 + return AlertWithTwoActions(
126 + alertTitle: S.of(context).change_wallet_alert_title,
127 + alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
128 + leftButtonText: S.of(context).cancel,
129 + rightButtonText: S.of(context).change,
130 + actionLeftButton: () => Navigator.of(dialogContext).pop(false),
131 + actionRightButton: () => Navigator.of(dialogContext).pop(true));
132 + }) ??
133 + false;
134 +
135 + if (confirmed) {
136 + await _loadWallet(selectedWallet);
137 + }
138 + });
139 }
140
141 Image _imageFor({required WalletType type}) {