diff --git a/drongo b/drongo index 533791ed..e974c3f4 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 533791edcf38a6ca05857483df15a5c54a4554f0 +Subproject commit e974c3f4223d1771aa59013c31311cf3d85e0915 diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DeviceAddressDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/DeviceAddressDialog.java index 81c57615..b1629c9d 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/DeviceAddressDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/DeviceAddressDialog.java @@ -1,22 +1,22 @@ package com.sparrowwallet.sparrow.control; import com.google.common.eventbus.Subscribe; -import com.sparrowwallet.drongo.KeyDerivation; +import com.sparrowwallet.drongo.OutputDescriptor; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.event.AddressDisplayedEvent; import com.sparrowwallet.sparrow.io.Device; -import java.util.List; +import java.util.stream.Collectors; public class DeviceAddressDialog extends DeviceDialog { private final Wallet wallet; - private final KeyDerivation keyDerivation; + private final OutputDescriptor outputDescriptor; - public DeviceAddressDialog(List operationFingerprints, Wallet wallet, KeyDerivation keyDerivation) { - super(operationFingerprints); + public DeviceAddressDialog(Wallet wallet, OutputDescriptor outputDescriptor) { + super(outputDescriptor.getExtendedPublicKeys().stream().map(extKey -> outputDescriptor.getKeyDerivation(extKey).getMasterFingerprint()).collect(Collectors.toList())); this.wallet = wallet; - this.keyDerivation = keyDerivation; + this.outputDescriptor = outputDescriptor; EventManager.get().register(this); setOnCloseRequest(event -> { @@ -26,7 +26,7 @@ public class DeviceAddressDialog extends DeviceDialog { @Override protected DevicePane getDevicePane(Device device) { - return new DevicePane(wallet, keyDerivation, device); + return new DevicePane(wallet, outputDescriptor, device); } @Subscribe diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DeviceDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/DeviceDialog.java index e7c33a64..016d7de0 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/DeviceDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/DeviceDialog.java @@ -101,6 +101,7 @@ public abstract class DeviceDialog extends Dialog { Platform.runLater(() -> EventManager.get().post(new UsbDeviceEvent(devices))); }); enumerateService.setOnFailed(workerStateEvent -> { + deviceAccordion.getPanes().clear(); scanBox.setVisible(true); scanLabel.setText(workerStateEvent.getSource().getException().getMessage()); }); diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java index 2ba81f66..10c24f52 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java @@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.control; import com.sparrowwallet.drongo.ExtendedKey; import com.sparrowwallet.drongo.KeyDerivation; +import com.sparrowwallet.drongo.OutputDescriptor; import com.sparrowwallet.drongo.crypto.ChildNumber; import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.psbt.PSBT; @@ -15,7 +16,6 @@ import com.sparrowwallet.sparrow.event.MessageSignedEvent; import com.sparrowwallet.sparrow.event.PSBTSignedEvent; import com.sparrowwallet.sparrow.io.Device; import com.sparrowwallet.sparrow.io.Hwi; -import com.sparrowwallet.drongo.wallet.WalletModel; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; @@ -25,7 +25,6 @@ import javafx.scene.Node; import javafx.scene.control.*; import javafx.scene.layout.*; import org.controlsfx.control.textfield.CustomPasswordField; -import org.controlsfx.control.textfield.CustomTextField; import org.controlsfx.control.textfield.TextFields; import org.controlsfx.glyphfont.Glyph; import org.controlsfx.validation.ValidationResult; @@ -36,6 +35,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; +import java.util.stream.Collectors; public class DevicePane extends TitledDescriptionPane { private static final Logger log = LoggerFactory.getLogger(DevicePane.class); @@ -43,6 +43,7 @@ public class DevicePane extends TitledDescriptionPane { private final DeviceOperation deviceOperation; private final Wallet wallet; private final PSBT psbt; + private final OutputDescriptor outputDescriptor; private final KeyDerivation keyDerivation; private final String message; private final Device device; @@ -63,6 +64,7 @@ public class DevicePane extends TitledDescriptionPane { this.deviceOperation = DeviceOperation.IMPORT; this.wallet = wallet; this.psbt = null; + this.outputDescriptor = null; this.keyDerivation = null; this.message = null; this.device = device; @@ -83,6 +85,7 @@ public class DevicePane extends TitledDescriptionPane { this.deviceOperation = DeviceOperation.SIGN; this.wallet = null; this.psbt = psbt; + this.outputDescriptor = null; this.keyDerivation = null; this.message = null; this.device = device; @@ -98,12 +101,13 @@ public class DevicePane extends TitledDescriptionPane { buttonBox.getChildren().addAll(setPassphraseButton, signButton); } - public DevicePane(Wallet wallet, KeyDerivation keyDerivation, Device device) { + public DevicePane(Wallet wallet, OutputDescriptor outputDescriptor, Device device) { super(device.getModel().toDisplayString(), "", "", "image/" + device.getType() + ".png"); this.deviceOperation = DeviceOperation.DISPLAY_ADDRESS; this.wallet = wallet; this.psbt = null; - this.keyDerivation = keyDerivation; + this.outputDescriptor = outputDescriptor; + this.keyDerivation = null; this.message = null; this.device = device; @@ -123,6 +127,7 @@ public class DevicePane extends TitledDescriptionPane { this.deviceOperation = DeviceOperation.SIGN_MESSAGE; this.wallet = wallet; this.psbt = null; + this.outputDescriptor = null; this.keyDerivation = keyDerivation; this.message = message; this.device = device; @@ -233,7 +238,8 @@ public class DevicePane extends TitledDescriptionPane { displayAddressButton.managedProperty().bind(displayAddressButton.visibleProperty()); displayAddressButton.setVisible(false); - if(device.getFingerprint() != null && !device.getFingerprint().equals(keyDerivation.getMasterFingerprint())) { + List fingerprints = outputDescriptor.getExtendedPublicKeys().stream().map(extKey -> outputDescriptor.getKeyDerivation(extKey).getMasterFingerprint()).collect(Collectors.toList()); + if(device.getFingerprint() != null && !fingerprints.contains(device.getFingerprint())) { displayAddressButton.setDisable(true); } } @@ -471,7 +477,7 @@ public class DevicePane extends TitledDescriptionPane { } private void displayAddress() { - Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(device, passphrase.get(), wallet.getScriptType(), keyDerivation.getDerivationPath()); + Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(device, passphrase.get(), wallet.getScriptType(), outputDescriptor); displayAddressService.setOnSucceeded(successEvent -> { String address = displayAddressService.getValue(); EventManager.get().post(new AddressDisplayedEvent(address)); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java index 0d3003c3..598a3e24 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java @@ -4,6 +4,7 @@ import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; import com.google.gson.*; import com.sparrowwallet.drongo.Network; +import com.sparrowwallet.drongo.OutputDescriptor; import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTParseException; @@ -29,7 +30,7 @@ import java.util.zip.ZipInputStream; public class Hwi { private static final Logger log = LoggerFactory.getLogger(Hwi.class); - private static final String TEMP_FILE_PREFIX = "hwi-1.2.1-"; + private static final String VERSION_PREFIX = "hwi-2.0.0-rc.2"; private static boolean isPromptActive = false; @@ -44,6 +45,9 @@ public class Hwi { String output = execute(command); Device[] devices = getGson().fromJson(output, Device[].class); + if(devices == null) { + throw new ImportException("Error scanning, check devices are ready"); + } return Arrays.stream(devices).filter(device -> device != null && device.getModel() != null).collect(Collectors.toList()); } catch(IOException e) { throw new ImportException(e); @@ -84,32 +88,40 @@ public class Hwi { if(result.get("xpub") != null) { return result.get("xpub").getAsString(); } else { - throw new ImportException("Could not retrieve xpub - reconnect your device and try again."); + JsonElement error = result.get("error"); + if(error != null) { + throw new ImportException(error.getAsString()); + } else { + throw new ImportException("Could not retrieve xpub - reconnect your device and try again."); + } } } catch(IOException e) { throw new ImportException(e); } } - public String displayAddress(Device device, String passphrase, ScriptType scriptType, String derivationPath) throws DisplayAddressException { + public String displayAddress(Device device, String passphrase, ScriptType scriptType, OutputDescriptor outputDescriptor) throws DisplayAddressException { try { - if(!List.of(ScriptType.P2PKH, ScriptType.P2SH_P2WPKH, ScriptType.P2WPKH).contains(scriptType)) { - throw new IllegalArgumentException("Cannot display address for script type " + scriptType + ": Only single sig types supported"); + if(!Arrays.asList(ScriptType.SINGLE_HASH_TYPES).contains(scriptType)) { + throw new IllegalArgumentException("Cannot display address for script type " + scriptType + ": Only single hash types supported"); } - String type = null; + String descriptor = outputDescriptor.toString().replace("sortedmulti", "multi"); + System.out.println(descriptor); + + String addrType = "legacy"; if(scriptType == ScriptType.P2SH_P2WPKH) { - type = "--sh_wpkh"; + addrType = "sh_wit"; } else if(scriptType == ScriptType.P2WPKH) { - type = "--wpkh"; + addrType = "wit"; } isPromptActive = false; String output; if(passphrase != null && !passphrase.isEmpty() && device.getModel().externalPassphraseEntry()) { - output = execute(getDeviceCommand(device, passphrase, Command.DISPLAY_ADDRESS, "--path", derivationPath, type)); + output = execute(getDeviceCommand(device, passphrase, Command.DISPLAY_ADDRESS, "--desc", descriptor, "--addr-type", addrType)); } else { - output = execute(getDeviceCommand(device, Command.DISPLAY_ADDRESS, "--path", derivationPath, type)); + output = execute(getDeviceCommand(device, Command.DISPLAY_ADDRESS, "--desc", descriptor, "--addr-type", addrType)); } JsonObject result = JsonParser.parseString(output).getAsJsonObject(); @@ -199,7 +211,7 @@ public class Hwi { private synchronized File getHwiExecutable(Command command) { File hwiExecutable = Config.get().getHwi(); if(hwiExecutable != null && hwiExecutable.exists()) { - if(command.isTestFirst() && (!hwiExecutable.getAbsolutePath().contains(TEMP_FILE_PREFIX) || !testHwi(hwiExecutable))) { + if(command.isTestFirst() && (!hwiExecutable.getAbsolutePath().contains(VERSION_PREFIX) || !testHwi(hwiExecutable))) { if(Platform.getCurrent() == Platform.OSX) { deleteDirectory(hwiExecutable.getParentFile()); } else { @@ -218,8 +230,8 @@ public class Hwi { //The check will still happen on first invocation, but will not thereafter //See https://github.com/bitcoin-core/HWI/issues/327 for details if(platform == Platform.OSX) { - InputStream inputStream = Hwi.class.getResourceAsStream("/native/osx/x64/hwi-1.2.1-mac-amd64-signed.zip"); - Path tempHwiDirPath = Files.createTempDirectory(TEMP_FILE_PREFIX, PosixFilePermissions.asFileAttribute(ownerExecutableWritable)); + InputStream inputStream = Hwi.class.getResourceAsStream("/native/osx/x64/" + VERSION_PREFIX + "-mac-amd64-signed.zip"); + Path tempHwiDirPath = Files.createTempDirectory(VERSION_PREFIX, PosixFilePermissions.asFileAttribute(ownerExecutableWritable)); File tempHwiDir = tempHwiDirPath.toFile(); //tempHwiDir.deleteOnExit(); log.debug("Using temp HWI path: " + tempHwiDir.getAbsolutePath()); @@ -227,16 +239,20 @@ public class Hwi { File tempExec = null; ZipInputStream zis = new ZipInputStream(inputStream); ZipEntry zipEntry = zis.getNextEntry(); - while (zipEntry != null) { - File newFile = newFile(tempHwiDir, zipEntry, ownerExecutableWritable); - //newFile.deleteOnExit(); - FileOutputStream fos = new FileOutputStream(newFile); - ByteStreams.copy(zis, new FileOutputStream(newFile)); - fos.flush(); - fos.close(); + while(zipEntry != null) { + if(zipEntry.isDirectory()) { + newDirectory(tempHwiDir, zipEntry, ownerExecutableWritable); + } else { + File newFile = newFile(tempHwiDir, zipEntry, ownerExecutableWritable); + //newFile.deleteOnExit(); + FileOutputStream fos = new FileOutputStream(newFile); + ByteStreams.copy(zis, new FileOutputStream(newFile)); + fos.flush(); + fos.close(); - if (zipEntry.getName().equals("hwi")) { - tempExec = newFile; + if(zipEntry.getName().equals("hwi")) { + tempExec = newFile; + } } zipEntry = zis.getNextEntry(); @@ -250,10 +266,10 @@ public class Hwi { Path tempExecPath; if(platform == Platform.WINDOWS) { inputStream = Hwi.class.getResourceAsStream("/native/windows/x64/hwi.exe"); - tempExecPath = Files.createTempFile(TEMP_FILE_PREFIX, null); + tempExecPath = Files.createTempFile(VERSION_PREFIX, null); } else { inputStream = Hwi.class.getResourceAsStream("/native/linux/x64/hwi"); - tempExecPath = Files.createTempFile(TEMP_FILE_PREFIX, null, PosixFilePermissions.asFileAttribute(ownerExecutableWritable)); + tempExecPath = Files.createTempFile(VERSION_PREFIX, null, PosixFilePermissions.asFileAttribute(ownerExecutableWritable)); } File tempExec = tempExecPath.toFile(); @@ -299,6 +315,20 @@ public class Hwi { return directoryToBeDeleted.delete(); } + public static File newDirectory(File destinationDir, ZipEntry zipEntry, Set setFilePermissions) throws IOException { + String destDirPath = destinationDir.getCanonicalPath(); + + Path path = Path.of(destDirPath, zipEntry.getName()); + File destDir = Files.createDirectory(path, PosixFilePermissions.asFileAttribute(setFilePermissions)).toFile(); + + String destSubDirPath = destDir.getCanonicalPath(); + if(!destSubDirPath.startsWith(destDirPath + File.separator)) { + throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); + } + + return destDir; + } + public static File newFile(File destinationDir, ZipEntry zipEntry, Set setFilePermissions) throws IOException { String destDirPath = destinationDir.getCanonicalPath(); @@ -306,7 +336,7 @@ public class Hwi { File destFile = Files.createFile(path, PosixFilePermissions.asFileAttribute(setFilePermissions)).toFile(); String destFilePath = destFile.getCanonicalPath(); - if (!destFilePath.startsWith(destDirPath + File.separator)) { + if(!destFilePath.startsWith(destDirPath + File.separator)) { throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); } @@ -324,30 +354,41 @@ public class Hwi { private List getDeviceCommand(Device device, Command command) throws IOException { List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), command.toString())); - if(Network.get() != Network.MAINNET) { - elements.add(elements.size() - 1, "--testnet"); - } + addChainType(elements); return elements; } private List getDeviceCommand(Device device, Command command, String... commandData) throws IOException { List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), command.toString())); - if(Network.get() != Network.MAINNET) { - elements.add(elements.size() - 1, "--testnet"); - } + addChainType(elements); elements.addAll(Arrays.stream(commandData).filter(Objects::nonNull).collect(Collectors.toList())); return elements; } private List getDeviceCommand(Device device, String passphrase, Command command, String... commandData) throws IOException { List elements = new ArrayList<>(List.of(getHwiExecutable(command).getAbsolutePath(), "--device-path", device.getPath(), "--device-type", device.getType(), "--password", passphrase, command.toString())); - if(Network.get() != Network.MAINNET) { - elements.add(elements.size() - 1, "--testnet"); - } + addChainType(elements); elements.addAll(Arrays.stream(commandData).filter(Objects::nonNull).collect(Collectors.toList())); return elements; } + private void addChainType(List elements) { + if(Network.get() != Network.MAINNET) { + elements.add(elements.size() - 1, "--chain"); + elements.add(elements.size() - 1, getChainName(Network.get())); + } + } + + private String getChainName(Network network) { + if(network == Network.MAINNET) { + return "main"; + } else if(network == Network.TESTNET) { + return "test"; + } + + return network.toString(); + } + public static class EnumerateService extends Service> { private final String passphrase; @@ -430,13 +471,13 @@ public class Hwi { private final Device device; private final String passphrase; private final ScriptType scriptType; - private final String derivationPath; + private final OutputDescriptor outputDescriptor; - public DisplayAddressService(Device device, String passphrase, ScriptType scriptType, String derivationPath) { + public DisplayAddressService(Device device, String passphrase, ScriptType scriptType, OutputDescriptor outputDescriptor) { this.device = device; this.passphrase = passphrase; this.scriptType = scriptType; - this.derivationPath = derivationPath; + this.outputDescriptor = outputDescriptor; } @Override @@ -444,7 +485,7 @@ public class Hwi { return new Task<>() { protected String call() throws DisplayAddressException { Hwi hwi = new Hwi(); - return hwi.displayAddress(device, passphrase, scriptType, derivationPath); + return hwi.displayAddress(device, passphrase, scriptType, outputDescriptor); } }; } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/ReceiveController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/ReceiveController.java index 04e31a7d..3a454ab6 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/ReceiveController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/ReceiveController.java @@ -9,7 +9,7 @@ import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter; import com.sparrowwallet.drongo.KeyDerivation; import com.sparrowwallet.drongo.KeyPurpose; -import com.sparrowwallet.drongo.policy.PolicyType; +import com.sparrowwallet.drongo.OutputDescriptor; import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex; import com.sparrowwallet.drongo.wallet.Keystore; import com.sparrowwallet.drongo.wallet.KeystoreSource; @@ -17,10 +17,7 @@ import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.control.*; -import com.sparrowwallet.sparrow.event.ReceiveToEvent; -import com.sparrowwallet.sparrow.event.UsbDeviceEvent; -import com.sparrowwallet.sparrow.event.WalletHistoryChangedEvent; -import com.sparrowwallet.sparrow.event.WalletNodesChangedEvent; +import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.io.Device; import com.sparrowwallet.sparrow.io.Hwi; @@ -153,26 +150,26 @@ public class ReceiveController extends WalletFormController implements Initializ } private void updateDisplayAddress(List devices) { - //Can only display address for single sig wallets. See https://github.com/bitcoin-core/HWI/issues/224 Wallet wallet = getWalletForm().getWallet(); - if(wallet.getPolicyType().equals(PolicyType.SINGLE)) { - List addressDevices = devices.stream().filter(device -> wallet.getKeystores().get(0).getKeyDerivation().getMasterFingerprint().equals(device.getFingerprint())).collect(Collectors.toList()); - if(addressDevices.isEmpty()) { - addressDevices = devices.stream().filter(device -> device.getNeedsPinSent() || device.getNeedsPassphraseSent()).collect(Collectors.toList()); - } + OutputDescriptor walletDescriptor = OutputDescriptor.getOutputDescriptor(walletForm.getWallet()); + List walletFingerprints = walletDescriptor.getExtendedPublicKeys().stream().map(extKey -> walletDescriptor.getKeyDerivation(extKey).getMasterFingerprint()).collect(Collectors.toList()); - if(!addressDevices.isEmpty()) { - if(currentEntry != null) { - displayAddress.setVisible(true); - } + List addressDevices = devices.stream().filter(device -> walletFingerprints.contains(device.getFingerprint())).collect(Collectors.toList()); + if(addressDevices.isEmpty()) { + addressDevices = devices.stream().filter(device -> device.getNeedsPinSent() || device.getNeedsPassphraseSent()).collect(Collectors.toList()); + } - displayAddress.setUserData(addressDevices); - return; - } else if(currentEntry != null && wallet.getKeystores().stream().anyMatch(keystore -> keystore.getSource().equals(KeystoreSource.HW_USB))) { + if(!addressDevices.isEmpty()) { + if(currentEntry != null) { displayAddress.setVisible(true); - displayAddress.setUserData(null); - return; } + + displayAddress.setUserData(addressDevices); + return; + } else if(currentEntry != null && wallet.getKeystores().stream().anyMatch(keystore -> keystore.getSource().equals(KeystoreSource.HW_USB))) { + displayAddress.setVisible(true); + displayAddress.setUserData(null); + return; } displayAddress.setVisible(false); @@ -204,28 +201,27 @@ public class ReceiveController extends WalletFormController implements Initializ @SuppressWarnings("unchecked") public void displayAddress(ActionEvent event) { Wallet wallet = getWalletForm().getWallet(); - if(wallet.getPolicyType() == PolicyType.SINGLE && currentEntry != null) { - Keystore keystore = wallet.getKeystores().get(0); - KeyDerivation fullDerivation = keystore.getKeyDerivation().extend(currentEntry.getNode().getDerivation()); + if(currentEntry != null) { + OutputDescriptor addressDescriptor = OutputDescriptor.getOutputDescriptor(walletForm.getWallet(), currentEntry.getNode().getKeyPurpose(), currentEntry.getNode().getIndex()); List possibleDevices = (List)displayAddress.getUserData(); if(possibleDevices != null && !possibleDevices.isEmpty()) { if(possibleDevices.size() > 1 || possibleDevices.get(0).getNeedsPinSent() || possibleDevices.get(0).getNeedsPassphraseSent()) { - DeviceAddressDialog dlg = new DeviceAddressDialog(List.of(keystore.getKeyDerivation().getMasterFingerprint()), wallet, fullDerivation); + DeviceAddressDialog dlg = new DeviceAddressDialog(wallet, addressDescriptor); dlg.showAndWait(); } else { Device actualDevice = possibleDevices.get(0); - Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(actualDevice, "", wallet.getScriptType(), fullDerivation.getDerivationPath()); + Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(actualDevice, "", wallet.getScriptType(), addressDescriptor); displayAddressService.setOnFailed(failedEvent -> { Platform.runLater(() -> { - DeviceAddressDialog dlg = new DeviceAddressDialog(List.of(keystore.getKeyDerivation().getMasterFingerprint()), wallet, fullDerivation); + DeviceAddressDialog dlg = new DeviceAddressDialog(wallet, addressDescriptor); dlg.showAndWait(); }); }); displayAddressService.start(); } } else { - DeviceAddressDialog dlg = new DeviceAddressDialog(List.of(keystore.getKeyDerivation().getMasterFingerprint()), wallet, fullDerivation); + DeviceAddressDialog dlg = new DeviceAddressDialog(wallet, addressDescriptor); dlg.showAndWait(); } } @@ -261,6 +257,11 @@ public class ReceiveController extends WalletFormController implements Initializ return duplicateGlyph; } + @Subscribe + public void walletSettingsChanged(WalletSettingsChangedEvent event) { + displayAddress.setUserData(null); + } + @Subscribe public void receiveTo(ReceiveToEvent event) { if(event.getReceiveEntry().getWallet().equals(getWalletForm().getWallet())) { diff --git a/src/main/resources/native/linux/x64/hwi b/src/main/resources/native/linux/x64/hwi index 275fb4c3..19b8cd66 100755 Binary files a/src/main/resources/native/linux/x64/hwi and b/src/main/resources/native/linux/x64/hwi differ diff --git a/src/main/resources/native/osx/x64/hwi-1.2.1-mac-amd64-signed.zip b/src/main/resources/native/osx/x64/hwi-2.0.0-rc.2-mac-amd64-signed.zip similarity index 63% rename from src/main/resources/native/osx/x64/hwi-1.2.1-mac-amd64-signed.zip rename to src/main/resources/native/osx/x64/hwi-2.0.0-rc.2-mac-amd64-signed.zip index 4f8cda2e..0b48e351 100755 Binary files a/src/main/resources/native/osx/x64/hwi-1.2.1-mac-amd64-signed.zip and b/src/main/resources/native/osx/x64/hwi-2.0.0-rc.2-mac-amd64-signed.zip differ diff --git a/src/main/resources/native/windows/x64/hwi.exe b/src/main/resources/native/windows/x64/hwi.exe index 0ab3bb99..07552861 100755 Binary files a/src/main/resources/native/windows/x64/hwi.exe and b/src/main/resources/native/windows/x64/hwi.exe differ