Implement DisplayAddressAsync
MODIFY
WalletWasabi.Tests/HwiTests/DeviceConnectedTests/Katas.cs
WalletWasabi.Tests/HwiTests/DeviceConnectedTests/Katas.cs
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using WalletWasabi.Hwi2;
using WalletWasabi.Hwi2.Exceptions;
using WalletWasabi.Hwi2.Models;
+using WalletWasabi.KeyManagement;
using Xunit;
namespace WalletWasabi.Tests.HwiTests.DeviceConnectedTests
@@ -34,6 +35,9 @@ namespace WalletWasabi.Tests.HwiTests.DeviceConnectedTests
//
// Connect an already initialized device and unlock it.
// Run this test.
+ // displayaddress request: refuse
+ // displayaddress request: confirm
+ // displayaddress request: confirm
//
// --- USER INTERACTIONS ---
@@ -54,13 +58,33 @@ namespace WalletWasabi.Tests.HwiTests.DeviceConnectedTests
await Assert.ThrowsAsync<HwiException>(async () => await client.BackupAsync(deviceType, devicePath, cts.Token));
// Trezor T doesn't support it.
- var ex = await Assert.ThrowsAsync<HwiException>(async () => await client.PromptPinAsync(deviceType, devicePath, cts.Token));
-
+ await Assert.ThrowsAsync<HwiException>(async () => await client.PromptPinAsync(deviceType, devicePath, cts.Token));
+ // Trezor T doesn't support it.
await Assert.ThrowsAsync<HwiException>(async () => await client.SendPinAsync(deviceType, devicePath, 1111, cts.Token));
- ExtPubKey xpub = await client.GetXpubAsync(deviceType, devicePath, cts.Token);
- Assert.NotNull(xpub);
- // ToDo: displayaddress
+ KeyPath keyPath1 = KeyManager.DefaultAccountKeyPath;
+ KeyPath keyPath2 = KeyManager.DefaultAccountKeyPath.Derive(1);
+ ExtPubKey xpub1 = await client.GetXpubAsync(deviceType, devicePath, keyPath1, cts.Token);
+ ExtPubKey xpub2 = await client.GetXpubAsync(deviceType, devicePath, keyPath2, cts.Token);
+ Assert.NotNull(xpub1);
+ Assert.NotNull(xpub2);
+ Assert.NotEqual(xpub1, xpub2);
+
+ // USER SHOULD REFUSE ACTION
+ await Assert.ThrowsAsync<HwiException>(async () => await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token));
+
+ // USER: CONFIRM
+ BitcoinWitPubKeyAddress address1 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath1, cts.Token);
+ // USER: CONFIRM
+ BitcoinWitPubKeyAddress address2 = await client.DisplayAddressAsync(deviceType, devicePath, keyPath2, cts.Token);
+ Assert.NotNull(address1);
+ Assert.NotNull(address2);
+ Assert.NotEqual(address1, address2);
+ var expectedAddress1 = xpub1.PubKey.GetAddress(ScriptPubKeyType.Segwit, client.Network);
+ var expectedAddress2 = xpub2.PubKey.GetAddress(ScriptPubKeyType.Segwit, client.Network);
+ Assert.Equal(expectedAddress1, address1);
+ Assert.Equal(expectedAddress2, address2);
+
// ToDo: signmessage
// ToDo: signtx
// ToDo: --fingerprint

MODIFY
WalletWasabi.Tests/HwiTests/NoDeviceConnectedTests/HwiDefaultResponseTests.cs
WalletWasabi.Tests/HwiTests/NoDeviceConnectedTests/HwiDefaultResponseTests.cs
@@ -82,7 +82,6 @@ namespace WalletWasabi.Tests.HwiTests.NoDeviceConnectedTests
await Assert.ThrowsAsync<OperationCanceledException>(async () => await client.GetHelpAsync(cts.Token));
await Assert.ThrowsAsync<OperationCanceledException>(async () => await client.EnumerateAsync(cts.Token));
await Assert.ThrowsAsync<OperationCanceledException>(async () => await client.SetupAsync(cts.Token));
- await Assert.ThrowsAsync<OperationCanceledException>(async () => await client.DisplayAddressAsync(cts.Token));
}
}
@@ -121,9 +120,7 @@ namespace WalletWasabi.Tests.HwiTests.NoDeviceConnectedTests
client.EnumerateAsync(cts.Token),
client.EnumerateAsync(cts.Token),
client.SetupAsync(cts.Token),
- client.SetupAsync(cts.Token),
- client.DisplayAddressAsync(cts.Token),
- client.DisplayAddressAsync(cts.Token)
+ client.SetupAsync(cts.Token)
};
cts.CancelAfter(ReasonableRequestTimeout * tasks.Count);
@@ -140,11 +137,6 @@ namespace WalletWasabi.Tests.HwiTests.NoDeviceConnectedTests
{
await Assert.ThrowsAsync<HwiException>(async () => await client.SetupAsync(cts.Token));
}
-
- using (var cts = new CancellationTokenSource(ReasonableRequestTimeout))
- {
- await Assert.ThrowsAsync<HwiException>(async () => await client.DisplayAddressAsync(cts.Token));
- }
}
#endregion Tests

MODIFY
WalletWasabi.Tests/HwiTests/NoDeviceConnectedTests/MockedDeviceTests.cs
WalletWasabi.Tests/HwiTests/NoDeviceConnectedTests/MockedDeviceTests.cs
@@ -9,6 +9,7 @@ using WalletWasabi.Helpers;
using WalletWasabi.Hwi2;
using WalletWasabi.Hwi2.Exceptions;
using WalletWasabi.Hwi2.Models;
+using WalletWasabi.KeyManagement;
using Xunit;
namespace WalletWasabi.Tests.HwiTests.NoDeviceConnectedTests
@@ -64,7 +65,8 @@ namespace WalletWasabi.Tests.HwiTests.NoDeviceConnectedTests
Assert.Equal("The PIN has already been sent to this device", sendpin.Message);
Assert.Equal(HwiErrorCode.DeviceAlreadyUnlocked, sendpin.ErrorCode);
- ExtPubKey xpub = await client.GetXpubAsync(deviceType, devicePath, cts.Token);
+ KeyPath keyPath = KeyManager.DefaultAccountKeyPath;
+ ExtPubKey xpub = await client.GetXpubAsync(deviceType, devicePath, keyPath, cts.Token);
var expecteXpub = NBitcoinHelpers.BetterParseExtPubKey("xpub6DHjDx4gzLV37gJWMxYJAqyKRGN46MT61RHVizdU62cbVUYu9L95cXKzX62yJ2hPbN11EeprS8sSn8kj47skQBrmycCMzFEYBQSntVKFQ5M");
Assert.Equal(expecteXpub, xpub);
}

MODIFY
WalletWasabi/Hwi2/HwiClient.cs
WalletWasabi/Hwi2/HwiClient.cs
@@ -90,12 +90,12 @@ namespace WalletWasabi.Hwi2
cancel).ConfigureAwait(false);
}
- public async Task<ExtPubKey> GetXpubAsync(HardwareWalletVendors deviceType, string devicePath, CancellationToken cancel)
+ public async Task<ExtPubKey> GetXpubAsync(HardwareWalletVendors deviceType, string devicePath, KeyPath keyPath, CancellationToken cancel)
{
var response = await SendCommandAsync(
options: new[] { HwiOption.DevicePath(devicePath), HwiOption.DeviceType(deviceType) },
command: HwiCommands.GetXpub,
- commandArguments: KeyManager.DefaultAccountKeyPath.ToString(true, "h"),
+ commandArguments: keyPath.ToString(true, "h"),
cancel).ConfigureAwait(false);
var extPubKey = HwiParser.ParseExtPubKey(response);
@@ -103,6 +103,19 @@ namespace WalletWasabi.Hwi2
return extPubKey;
}
+ public async Task<BitcoinWitPubKeyAddress> DisplayAddressAsync(HardwareWalletVendors deviceType, string devicePath, KeyPath keyPath, CancellationToken cancel)
+ {
+ var response = await SendCommandAsync(
+ options: new[] { HwiOption.DevicePath(devicePath), HwiOption.DeviceType(deviceType) },
+ command: HwiCommands.DisplayAddress,
+ commandArguments: $"--path {keyPath.ToString(true, "h")} --wpkh",
+ cancel).ConfigureAwait(false);
+
+ var address = HwiParser.ParseAddress(response, Network);
+
+ return address as BitcoinWitPubKeyAddress;
+ }
+
public async Task WipeAsync(HardwareWalletVendors deviceType, string devicePath, CancellationToken cancel)
{
await SendCommandAsync(
@@ -174,12 +187,6 @@ namespace WalletWasabi.Hwi2
return responseString;
}
- public async Task<string> DisplayAddressAsync(CancellationToken cancel)
- {
- string responseString = await SendCommandAsync(options: null, command: HwiCommands.DisplayAddress, commandArguments: null, cancel).ConfigureAwait(false);
- return responseString;
- }
-
#endregion Commands
#region Helpers

MODIFY
WalletWasabi/Hwi2/Parsers/HwiParser.cs
WalletWasabi/Hwi2/Parsers/HwiParser.cs
@@ -160,6 +160,20 @@ namespace WalletWasabi.Hwi2.Parsers
}
}
+ public static BitcoinAddress ParseAddress(string json, Network network)
+ {
+ if (JsonHelpers.TryParseJToken(json, out JToken token))
+ {
+ var addressString = token["address"]?.ToString()?.Trim() ?? null;
+ var address = BitcoinAddress.Create(addressString, network);
+ return address;
+ }
+ else
+ {
+ throw new FormatException($"Could not parse extpubkey: {json}");
+ }
+ }
+
public static HwiEnumerateEntry ParseHwiEnumerateEntry(JObject json)
{
JToken typeToken = json["type"];

Implement DisplayAddressAsync