Catch Ledger exceptions.
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
@@ -293,7 +293,9 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
MainWindowViewModel.Instance.StatusBar.AddStatus(acquiringSignatureFromHardwareWalletStatusText);
signedPsbt = await HwiProcessManager.SignTxAsync(KeyManager.HardwareWalletInfo, result.Psbt);
}
- catch (IOException ex) when (ex.Message.Contains("device not found", StringComparison.OrdinalIgnoreCase))
+ catch (IOException ex) when (ex.Message.Contains("device not found", StringComparison.OrdinalIgnoreCase)
+ || ex.Message.Contains("Invalid status 6f04", StringComparison.OrdinalIgnoreCase) // It comes when device asleep too.
+ || ex.Message.Contains("Device is asleep", StringComparison.OrdinalIgnoreCase))
{
MainWindowViewModel.Instance.StatusBar.AddStatus(connectingToHardwareWalletStatusText);
// The user may changed USB port. Try again with new enumeration.
@@ -347,6 +349,13 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
private async Task<bool> TryRefreshHardwareWalletInfoAsync(KeyManager keyManager)
{
var hwis = await HwiProcessManager.EnumerateAsync();
+
+ bool ledgerNotReady = hwis.Any(x => x.Type == HardwareWalletType.Ledger && !x.Ready);
+ if (ledgerNotReady) // For Ledger you have to log into your "Bitcoin" account.
+ {
+ throw new InvalidOperationException("Log into your Bitcoin account on your Ledger. If you're already logged in, log out and log in again.");
+ }
+
var fingerprint = keyManager.MasterFingerprint;
if (fingerprint is null) return false;

MODIFY
WalletWasabi.Gui/Models/LoadWalletEntry.cs
WalletWasabi.Gui/Models/LoadWalletEntry.cs
@@ -26,6 +26,10 @@ namespace WalletWasabi.Gui.Models
{
WalletName = hwi.Type.ToString() + $" - Not Initialized";
}
+ else if (!hwi.Ready)
+ {
+ WalletName = hwi.Type.ToString() + $" - Device Not Ready";
+ }
else
{
WalletName = hwi.Type.ToString() + $" - Error: {hwi.Error}";

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/LoadWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/LoadWalletViewModel.cs
@@ -156,7 +156,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
set => this.RaiseAndSetIfChanged(ref _successMessage, value);
}
- private void SetWarningMessage(string message)
+ public void SetWarningMessage(string message)
{
WarningMessage = message;
ValidationMessage = "";
@@ -324,7 +324,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
LoadWalletEntry found = Wallets?.FirstOrDefault(x => x.HardwareWalletInfo.Path == hwi.Path);
// If something changed then update.
if (found?.HardwareWalletInfo != null &&
- (found.HardwareWalletInfo.Initialized != hwi.Initialized || found.HardwareWalletInfo.MasterFingerprint != hwi.MasterFingerprint || found.HardwareWalletInfo.Error != hwi.Error))
+ (found.HardwareWalletInfo.Initialized != hwi.Initialized || found.HardwareWalletInfo.Ready != hwi.Ready || found.HardwareWalletInfo.MasterFingerprint != hwi.MasterFingerprint || found.HardwareWalletInfo.Error != hwi.Error))
{
toRemove.Add(found);
changed = true;

MODIFY
WalletWasabi/Hwi/HwiProcessManager.cs
WalletWasabi/Hwi/HwiProcessManager.cs
@@ -40,6 +40,8 @@ namespace WalletWasabi.Hwi
{
var psbtString = psbt.ToBase64();
var networkString = Network == Network.Main ? "" : "--testnet";
+ try
+ {
JToken jtok = await SendCommandAsync($"{networkString} --device-type \"{hardwareWalletInfo.Type.ToString().ToLowerInvariant()}\" --device-path \"{hardwareWalletInfo.Path}\" signtx {psbtString}", isMutexPriority: true);
JObject json = jtok as JObject;
var signedPsbtString = json.Value<string>("psbt");
@@ -52,6 +54,18 @@ namespace WalletWasabi.Hwi
return signedPsbt;
}
+ catch (IOException ex) when (hardwareWalletInfo.Type == HardwareWalletType.Ledger
+ && (ex.Message.Contains("sign_tx cancelled", StringComparison.OrdinalIgnoreCase)
+ || ex.Message.Contains("open failed", StringComparison.OrdinalIgnoreCase)))
+ {
+ throw new IOException("Log into your Bitcoin account on your Ledger. If you're already logged in, log out and log in again.");
+ }
+ catch (IOException ex) when (hardwareWalletInfo.Type == HardwareWalletType.Ledger
+ && ex.Message.Contains("Bad argument", StringComparison.OrdinalIgnoreCase))
+ {
+ throw new IOException("Ledger refused to sign the transaction.");
+ }
+ }
/// <summary>
/// Acquire bech32 xpub on path: m/84h/0h/0h

MODIFY
WalletWasabi/Hwi/Models/HardwareWalletInfo.cs
WalletWasabi/Hwi/Models/HardwareWalletInfo.cs
@@ -26,18 +26,27 @@ namespace WalletWasabi.Hwi.Models
Path = path;
Error = error;
- if (Error != null && Error.Contains("Not initialized", StringComparison.InvariantCultureIgnoreCase))
+ Ready = true;
+ Initialized = true;
+ if (Error != null)
+ {
+ if (Error.Contains("Not initialized", StringComparison.OrdinalIgnoreCase))
{
Initialized = false;
}
- else
+ else if (Type == HardwareWalletType.Ledger &&
+ (Error.Contains("get_pubkey_at_path canceled", StringComparison.OrdinalIgnoreCase)
+ || Error.Contains("Invalid status 6f04", StringComparison.OrdinalIgnoreCase) // It comes when device asleep too.
+ || Error.Contains("Device is asleep", StringComparison.OrdinalIgnoreCase)))
{
- Initialized = true;
+ Ready = false;
+ }
}
}
public HDFingerprint? MasterFingerprint { get; }
public bool Initialized { get; }
+ public bool Ready { get; }
public string SerialNumber { get; }
public HardwareWalletType Type { get; }
public string Path { get; }

Catch Ledger exceptions.