mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-11-13 09:04:09 +01:00
V6.4.5 rc (#3639)
* v6.4.5 Release candidate * Apply patches for BLE session, locktime prompt, and monero coincontrol on hww [skip ci] * include the fix for bluetooth prompt showing on app start * include the fix for bluetooth prompt showing on app start
This commit is contained in:
@@ -27,7 +27,7 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
||||
String get title => 'Exolix';
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
bool get isAvailable => false;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@@ -48,6 +48,7 @@ import "package:cake_wallet/src/widgets/standard_checkbox.dart";
|
||||
import "package:cake_wallet/utils/payment_request.dart";
|
||||
import "package:cake_wallet/utils/show_pop_up.dart";
|
||||
import "package:cake_wallet/view_model/contact_list/contact_list_view_model.dart";
|
||||
import "package:cake_wallet/view_model/hardware_wallet/trezor_connect_view_model.dart";
|
||||
import "package:cake_wallet/view_model/link_view_model.dart";
|
||||
import "package:cake_wallet/view_model/send/output.dart";
|
||||
import "package:cake_wallet/view_model/send/send_view_model.dart";
|
||||
@@ -861,8 +862,23 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
}
|
||||
|
||||
if (widget.sendViewModel.wallet.isHardwareWallet) {
|
||||
final trezorVM = widget.sendViewModel.hardwareWalletViewModel;
|
||||
if (trezorVM is TrezorConnectViewModel &&
|
||||
widget.sendViewModel.walletType == WalletType.bitcoin &&
|
||||
trezorVM.isConnected(WalletType.bitcoin) &&
|
||||
!trezorVM.isSessionFor(widget.sendViewModel.wallet)) {
|
||||
// The live session belongs to another wallet (passphrase); open one for this wallet
|
||||
await trezorVM.dropSession();
|
||||
}
|
||||
|
||||
if (!widget.sendViewModel.hardwareWalletViewModel!
|
||||
.isConnected(widget.sendViewModel.walletType)) {
|
||||
final hardwareWalletVM = widget.sendViewModel.hardwareWalletViewModel;
|
||||
if (hardwareWalletVM is TrezorConnectViewModel &&
|
||||
widget.sendViewModel.walletType == WalletType.bitcoin) {
|
||||
hardwareWalletVM.prepareReconnect(widget.sendViewModel.wallet);
|
||||
}
|
||||
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.connectDevices,
|
||||
arguments: ConnectDevicePageParams(
|
||||
@@ -875,6 +891,9 @@ class _NewSendPageState extends State<NewSendPage> {
|
||||
isReconnect: false,
|
||||
),
|
||||
);
|
||||
if (hardwareWalletVM is TrezorConnectViewModel) {
|
||||
hardwareWalletVM.cancelReconnect();
|
||||
}
|
||||
|
||||
// Recheck to handle tap-backs
|
||||
if (!widget.sendViewModel.hardwareWalletViewModel!
|
||||
|
||||
@@ -4,10 +4,17 @@ import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HardwareWalletProceedOnDeviceMessage extends StatelessWidget {
|
||||
const HardwareWalletProceedOnDeviceMessage({super.key, required this.hardwareWalletType});
|
||||
const HardwareWalletProceedOnDeviceMessage({
|
||||
super.key,
|
||||
required this.hardwareWalletType,
|
||||
this.note,
|
||||
});
|
||||
|
||||
final HardwareWalletType hardwareWalletType;
|
||||
|
||||
/// Optional hint about what the device is going to ask
|
||||
final String? note;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
@@ -35,7 +42,17 @@ class HardwareWalletProceedOnDeviceMessage extends StatelessWidget {
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
)
|
||||
),
|
||||
if (note != null)
|
||||
Text(
|
||||
note!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -6,6 +6,8 @@ import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
@@ -61,7 +63,12 @@ class SendConfirmBottomWidget extends StatelessWidget {
|
||||
);
|
||||
case IsAwaitingDeviceResponseState:
|
||||
return HardwareWalletProceedOnDeviceMessage(
|
||||
hardwareWalletType: sendViewModel.wallet.hardwareWalletType!);
|
||||
hardwareWalletType: sendViewModel.wallet.hardwareWalletType!,
|
||||
note: sendViewModel.walletType == WalletType.bitcoin &&
|
||||
sendViewModel.wallet.hardwareWalletType == HardwareWalletType.trezor
|
||||
? S.of(context).trezor_locktime_notice
|
||||
: null,
|
||||
);
|
||||
case TransactionCommitting:
|
||||
return LoadingBottomWidget(
|
||||
text: "${S.of(context).sending}...",
|
||||
|
||||
@@ -149,6 +149,49 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
Completer<String?>? _pinCompleter;
|
||||
Completer<TrezorDeviceSettings>? _settingsCompleter;
|
||||
|
||||
/// Settings that successfully opened a session, kept in memory (never persisted) per wallet id
|
||||
/// so a reconnect during a send doesn't ask for the wallet options / passphrase again.
|
||||
final Map<String, TrezorDeviceSettings> _sessionSettings = {};
|
||||
TrezorDeviceSettings? _lastUsedSettings;
|
||||
String? _reconnectWalletId;
|
||||
|
||||
/// The wallet the live session (and with it the passphrase) belongs to, null if unknown
|
||||
String? _sessionWalletId;
|
||||
|
||||
/// Call right before opening the connect page to reconnect the device for [wallet].
|
||||
/// Only then the settings of the previous session are reused; creating or restoring a wallet
|
||||
/// always asks for them.
|
||||
void prepareReconnect(WalletBase wallet) => _reconnectWalletId = wallet.id;
|
||||
|
||||
/// Call when the connect page opened after [prepareReconnect] is closed, so an attempt that was
|
||||
/// backed out of can never leak its settings into a later, unrelated connect (e.g. a restore).
|
||||
void cancelReconnect() => _reconnectWalletId = null;
|
||||
|
||||
/// Call once a wallet was created / restored with the live session
|
||||
void bindSessionToWallet(WalletBase wallet) {
|
||||
_sessionWalletId = wallet.id;
|
||||
final settings = _lastUsedSettings;
|
||||
if (settings != null) {
|
||||
_sessionSettings[wallet.id] = settings;
|
||||
_lastUsedSettings = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// False if the live session is known to belong to another wallet, e.g. one with a different
|
||||
/// passphrase. Using it would only fail when signing.
|
||||
bool isSessionFor(WalletBase wallet) =>
|
||||
_sessionWalletId == null || _sessionWalletId == wallet.id;
|
||||
|
||||
Future<void> dropSession() async {
|
||||
final client = _client;
|
||||
_client = null;
|
||||
_sessionWalletId = null;
|
||||
_lastUsedSettings = null;
|
||||
try {
|
||||
await client?.connection.disconnect();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
@observable
|
||||
TrezorParingState paringState = TrezorParingState.initial;
|
||||
|
||||
@@ -172,6 +215,10 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
isConnecting = true;
|
||||
paringState = TrezorParingState.initial;
|
||||
|
||||
final reconnectWalletId = _reconnectWalletId;
|
||||
_reconnectWalletId = null;
|
||||
final reusedSettings = reconnectWalletId != null ? _sessionSettings[reconnectWalletId] : null;
|
||||
|
||||
try {
|
||||
final trezorInterface =
|
||||
device.connectionType == HardwareWalletConnectionType.ble ? trezorBLE : trezorUSB;
|
||||
@@ -226,10 +273,15 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
_state!.pairingCredentials.any((c) => c.autoconnect == true);
|
||||
final isAutoPairingAvailable = _client is sdk.TrezorClientV2 && !hasAutoPairingCredentials;
|
||||
|
||||
paringState =
|
||||
TrezorParingState.awaitingSettings(isAutoPairingAvailable: isAutoPairingAvailable);
|
||||
_settingsCompleter = Completer<TrezorDeviceSettings>();
|
||||
final settings = await _settingsCompleter!.future;
|
||||
final TrezorDeviceSettings settings;
|
||||
if (reusedSettings != null) {
|
||||
settings = reusedSettings;
|
||||
} else {
|
||||
paringState =
|
||||
TrezorParingState.awaitingSettings(isAutoPairingAvailable: isAutoPairingAvailable);
|
||||
_settingsCompleter = Completer<TrezorDeviceSettings>();
|
||||
settings = await _settingsCompleter!.future;
|
||||
}
|
||||
|
||||
paringState = TrezorParingState.awaitingPassphrase;
|
||||
if (settings.enableAutoParing && isAutoPairingAvailable) {
|
||||
@@ -249,18 +301,28 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
await _client!.createSession(passphrase);
|
||||
}
|
||||
|
||||
_lastUsedSettings = settings;
|
||||
_sessionWalletId = reconnectWalletId;
|
||||
paringState = TrezorParingState.success;
|
||||
return true;
|
||||
} catch (e) {
|
||||
await _client?.connection.disconnect();
|
||||
_client = null;
|
||||
_state = sdk.ThpState();
|
||||
_sessionWalletId = null;
|
||||
_lastUsedSettings = null;
|
||||
// Drop the (possibly half way through a handshake) state, the next attempt reloads the
|
||||
// saved pairing credentials instead of asking for the pairing code again.
|
||||
_state = null;
|
||||
if (reconnectWalletId != null) {
|
||||
_sessionSettings.remove(reconnectWalletId);
|
||||
}
|
||||
// rethrow;
|
||||
paringState = TrezorParingState.fail(e.toString());
|
||||
printV(e);
|
||||
return false;
|
||||
} finally {
|
||||
isConnecting = false;
|
||||
_reconnectWalletId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +361,13 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
|
||||
@override
|
||||
Future<void> initWallet(WalletBase wallet) async {
|
||||
// Only a session that was opened for this wallet may hand its settings to it
|
||||
final lastUsedSettings = _lastUsedSettings;
|
||||
if (lastUsedSettings != null && _sessionWalletId == wallet.id) {
|
||||
_sessionSettings[wallet.id] = lastUsedSettings;
|
||||
_lastUsedSettings = null;
|
||||
}
|
||||
|
||||
switch (wallet.type) {
|
||||
case WalletType.monero:
|
||||
return monero!.setHardwareWalletService(wallet, getHardwareWalletService(wallet.type));
|
||||
@@ -354,10 +423,30 @@ abstract class TrezorConnectViewModelBase extends HardwareWalletViewModel with S
|
||||
}
|
||||
}
|
||||
|
||||
void _connectionChangeListener(sdk.BleConnectionState event) {
|
||||
printV("Ledger Device State Changed: $event");
|
||||
if (event == sdk.BleConnectionState.disconnected && !isConnecting) {
|
||||
Future<void> _connectionChangeListener(sdk.BleConnectionState event) async {
|
||||
printV("Trezor Device State Changed: $event");
|
||||
if (event != sdk.BleConnectionState.disconnected || isConnecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
final client = _client;
|
||||
if (client == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The events aren't device specific, so check if it's actually our Trezor that is gone
|
||||
if (client.connection.connectionType == sdk.ConnectionType.ble) {
|
||||
try {
|
||||
final state = await sdk.UniversalBle.getConnectionState(client.connection.device.id);
|
||||
if (state == sdk.BleConnectionState.connected) {
|
||||
return;
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
if (identical(_client, client)) {
|
||||
_client = null;
|
||||
_sessionWalletId = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/hardware_wallet_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/trezor_connect_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||
@@ -103,6 +104,12 @@ abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with
|
||||
@override
|
||||
Future<WalletBase> process(WalletCredentials credentials) async {
|
||||
walletCreationService.changeWalletType(type: type);
|
||||
return walletCreationService.restoreFromHardwareWallet(credentials);
|
||||
final wallet = await walletCreationService.restoreFromHardwareWallet(credentials);
|
||||
|
||||
final hardwareWalletVM = this.hardwareWalletVM;
|
||||
if (hardwareWalletVM is TrezorConnectViewModel && type == WalletType.bitcoin) {
|
||||
hardwareWalletVM.bindSessionToWallet(wallet);
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user