diff --git a/drongo b/drongo index 60ac4280..33bf35e3 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 60ac42800222a487651b93529796d31e5a954b99 +Subproject commit 33bf35e3c4fdaed6e6b0d598efaa3f8f0406c266 diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DescriptorQRDisplayDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/DescriptorQRDisplayDialog.java index e844e923..ab1d2c24 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/DescriptorQRDisplayDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/DescriptorQRDisplayDialog.java @@ -3,13 +3,14 @@ package com.sparrowwallet.sparrow.control; import com.sparrowwallet.hummingbird.UR; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.io.PdfUtils; +import com.sparrowwallet.sparrow.io.bbqr.BBQR; import javafx.event.ActionEvent; import javafx.scene.control.*; import javafx.scene.control.Button; public class DescriptorQRDisplayDialog extends QRDisplayDialog { - public DescriptorQRDisplayDialog(String walletName, String outputDescriptor, UR ur) { - super(ur); + public DescriptorQRDisplayDialog(String walletName, String outputDescriptor, UR ur, BBQR bbqr, boolean selectBbqrButton) { + super(ur, bbqr, false, false, selectBbqrButton); DialogPane dialogPane = getDialogPane(); final ButtonType pdfButtonType = new javafx.scene.control.ButtonType("Save PDF...", ButtonBar.ButtonData.HELP_2); @@ -19,7 +20,7 @@ public class DescriptorQRDisplayDialog extends QRDisplayDialog { pdfButton.setGraphicTextGap(5); pdfButton.setGraphic(getGlyph(FontAwesome5.Glyph.FILE_PDF)); pdfButton.addEventFilter(ActionEvent.ACTION, event -> { - PdfUtils.saveOutputDescriptor(walletName, outputDescriptor, ur); + PdfUtils.saveOutputDescriptor(walletName, outputDescriptor, ur, isUseBbqrEncoding() ? bbqr : null); event.consume(); }); } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java index 1d0bbaad..7337b8be 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java @@ -171,11 +171,18 @@ public class FileWalletExportPane extends TitledDescriptionPane { } else if(exporter instanceof Bip129) { UR ur = UR.fromBytes(outputStream.toByteArray()); BBQR bbqr = new BBQR(BBQRType.UNICODE, outputStream.toByteArray()); - qrDisplayDialog = new QRDisplayDialog(ur, bbqr, false, true, false); + qrDisplayDialog = new QRDisplayDialog(ur, bbqr, false, false, false); } else if(exporter instanceof Descriptor) { + boolean addBbqrOption = exportWallet.getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().showBbqr()); + boolean selectBbqrOption = exportWallet.getKeystores().stream().allMatch(keystore -> keystore.getWalletModel().selectBbqr()); OutputDescriptor outputDescriptor = OutputDescriptor.getOutputDescriptor(exportWallet, KeyPurpose.DEFAULT_PURPOSES, null); CryptoOutput cryptoOutput = getCryptoOutput(exportWallet); - qrDisplayDialog = new DescriptorQRDisplayDialog(exportWallet.getFullDisplayName(), outputDescriptor.toString(true), cryptoOutput.toUR()); + BBQR bbqr = addBbqrOption ? new BBQR(BBQRType.UNICODE, outputDescriptor.toString(true).getBytes(StandardCharsets.UTF_8)) : null; + qrDisplayDialog = new DescriptorQRDisplayDialog(exportWallet.getFullDisplayName(), outputDescriptor.toString(true), cryptoOutput.toUR(), bbqr, selectBbqrOption); + } else if(exporter.getClass().equals(ColdcardMultisig.class)) { + UR ur = UR.fromBytes(outputStream.toByteArray()); + BBQR bbqr = new BBQR(BBQRType.UNICODE, outputStream.toByteArray()); + qrDisplayDialog = new QRDisplayDialog(ur, bbqr, false, false, true); } else { qrDisplayDialog = new QRDisplayDialog(outputStream.toString(StandardCharsets.UTF_8)); } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/QRDisplayDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/QRDisplayDialog.java index c2293d74..b89a7aab 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/QRDisplayDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/QRDisplayDialog.java @@ -259,6 +259,10 @@ public class QRDisplayDialog extends Dialog { } } + public boolean isUseBbqrEncoding() { + return useBbqrEncoding; + } + private void setUseBbqrEncoding(boolean useBbqrEncoding) { if(useBbqrEncoding) { this.useBbqrEncoding = true; diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java index 6614cb44..ccd4ee36 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java @@ -111,7 +111,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle @Override public String getKeystoreImportDescription(int account) { - return "Import file created by using the Settings > Multisig Wallets > Export XPUB > " + account + " feature on your Coldcard."; + return "Import file or QR created by using Advanced/Tools > Export Wallet > Sparrow Wallet" + (account > 0 ? " > 1 > " + account : "") + " on your Coldcard. For older firmware use Settings > Multisig Wallets > Export XPUB > " + account + "."; } @Override @@ -186,7 +186,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle @Override public String getWalletImportDescription() { - return "Import file created by using the Settings > Multisig Wallets > [Wallet Detail] > Coldcard Export feature on your Coldcard."; + return "Import file or QR created by using Settings > Multisig Wallets > [Wallet Detail] > Coldcard Export on your Coldcard."; } @Override @@ -239,7 +239,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle @Override public String getWalletExportDescription() { - return "Export file that can be read by your Coldcard using the Settings > Multisig Wallets > Import from File feature."; + return "Export file or QR that can be read by your Coldcard using Settings > Multisig Wallets > Import from File or QR."; } @Override diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java index a8ac9f30..7d7a9b41 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java @@ -30,7 +30,7 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport { @Override public String getKeystoreImportDescription(int account) { - return "Import file created by using the Advanced > MicroSD > Export Wallet > Generic JSON > " + account + " feature on your Coldcard. Note this requires firmware version 3.1.3 or later."; + return "Import file or QR created by using Advanced/Tools > Export Wallet > Sparrow Wallet" + (account > 0 ? " > 1 > " + account : "") + " on your Coldcard. For older firmware use Advanced > MicroSD > Export Wallet > Generic JSON > " + account + "."; } @Override diff --git a/src/main/java/com/sparrowwallet/sparrow/io/PdfUtils.java b/src/main/java/com/sparrowwallet/sparrow/io/PdfUtils.java index c833778f..e061c9d2 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/PdfUtils.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/PdfUtils.java @@ -22,6 +22,9 @@ import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.hummingbird.UR; import com.sparrowwallet.hummingbird.UREncoder; import com.sparrowwallet.sparrow.AppServices; +import com.sparrowwallet.sparrow.io.bbqr.BBQR; +import com.sparrowwallet.sparrow.io.bbqr.BBQREncoder; +import com.sparrowwallet.sparrow.io.bbqr.BBQREncoding; import javafx.embed.swing.SwingFXUtils; import javafx.stage.FileChooser; import javafx.stage.Stage; @@ -39,7 +42,7 @@ public class PdfUtils { private static final int QR_WIDTH = 480; private static final int QR_HEIGHT = 480; - public static void saveOutputDescriptor(String walletName, String outputDescriptor, UR ur) { + public static void saveOutputDescriptor(String walletName, String outputDescriptor, UR ur, BBQR bbqr) { Stage window = new Stage(); FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Save PDF"); @@ -56,9 +59,22 @@ public class PdfUtils { Chunk title = new Chunk("Output descriptor for " + walletName, titleFont); document.add(title); - UREncoder urEncoder = new UREncoder(ur, 2000, 10, 0); - String fragment = urEncoder.nextPart(); - if(urEncoder.isSinglePart()) { + String fragment = null; + if(bbqr != null) { + BBQREncoder bbqrEncoder = new BBQREncoder(bbqr.type(), BBQREncoding.ZLIB, bbqr.data(), 2000, 0); + if(bbqrEncoder.isSinglePart()) { + fragment = bbqrEncoder.nextPart(); + } + } + + if(fragment == null) { + UREncoder urEncoder = new UREncoder(ur, 2000, 10, 0); + if(urEncoder.isSinglePart()) { + fragment = urEncoder.nextPart(); + } + } + + if(fragment != null) { Image image = Image.getInstance(SwingFXUtils.fromFXImage(getQrCode(fragment), null), Color.WHITE); document.add(image); } diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java index e7f41d7d..22ca6af9 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java @@ -905,9 +905,9 @@ public class HeadersController extends TransactionFormController implements Init toggleButton.setSelected(false); //TODO: Remove once Cobo Vault support has been removed - boolean addLegacyEncodingOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COBO_VAULT)); - boolean addBbqrOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COLDCARD) || keystore.getSource().equals(KeystoreSource.SW_WATCH) || keystore.getSource().equals(KeystoreSource.SW_SEED)); - boolean selectBbqrOption = headersForm.getSigningWallet().getKeystores().stream().allMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COLDCARD)); + boolean addLegacyEncodingOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().showLegacyQR()); + boolean addBbqrOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().showBbqr()); + boolean selectBbqrOption = headersForm.getSigningWallet().getKeystores().stream().allMatch(keystore -> keystore.getWalletModel().selectBbqr()); //Don't include non witness utxo fields for segwit wallets when displaying the PSBT as a QR - it can add greatly to the time required for scanning boolean includeNonWitnessUtxos = !Arrays.asList(ScriptType.WITNESS_TYPES).contains(headersForm.getSigningWallet().getScriptType()); diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/MultisigBackupDialog.java b/src/main/java/com/sparrowwallet/sparrow/wallet/MultisigBackupDialog.java index 0f79c4dd..40530836 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/MultisigBackupDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/MultisigBackupDialog.java @@ -5,12 +5,16 @@ import com.sparrowwallet.hummingbird.UR; import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.io.PdfUtils; +import com.sparrowwallet.sparrow.io.bbqr.BBQR; +import com.sparrowwallet.sparrow.io.bbqr.BBQRType; import javafx.scene.Node; import javafx.scene.control.*; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import org.controlsfx.glyphfont.Glyph; +import java.nio.charset.StandardCharsets; + public class MultisigBackupDialog extends Dialog { private final Wallet wallet; private final String descriptor; @@ -71,7 +75,12 @@ public class MultisigBackupDialog extends Dialog { final ButtonBar.ButtonData buttonData = buttonType.getButtonData(); ButtonBar.setButtonData(pdfButton, buttonData); pdfButton.setOnAction(event -> { - PdfUtils.saveOutputDescriptor(wallet.getFullDisplayName(), descriptor, ur); + BBQR bbqr = null; + if(wallet.getKeystores().stream().allMatch(keystore -> keystore.getWalletModel().selectBbqr())) { + bbqr = new BBQR(BBQRType.UNICODE, descriptor.getBytes(StandardCharsets.UTF_8)); + } + + PdfUtils.saveOutputDescriptor(wallet.getFullDisplayName(), descriptor, ur, bbqr); }); button = pdfButton; diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java index 53f75702..9414f3b3 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java @@ -18,6 +18,8 @@ import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Storage; import com.sparrowwallet.sparrow.io.StorageException; +import com.sparrowwallet.sparrow.io.bbqr.BBQR; +import com.sparrowwallet.sparrow.io.bbqr.BBQRType; import com.sparrowwallet.sparrow.net.ElectrumServer; import com.sparrowwallet.sparrow.net.ServerType; import javafx.application.Platform; @@ -37,6 +39,7 @@ import tornadofx.control.Fieldset; import java.io.IOException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -376,8 +379,12 @@ public class SettingsController extends WalletFormController implements Initiali return; } + boolean addBbqrOption = walletForm.getWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().showBbqr()); + boolean selectBbqrOption = walletForm.getWallet().getKeystores().stream().allMatch(keystore -> keystore.getWalletModel().selectBbqr()); + UR cryptoOutputUR = cryptoOutput.toUR(); - QRDisplayDialog qrDisplayDialog = new DescriptorQRDisplayDialog(walletForm.getWallet().getFullDisplayName(), outputDescriptor.toString(true), cryptoOutputUR); + BBQR bbqr = addBbqrOption ? new BBQR(BBQRType.UNICODE, outputDescriptor.toString(true).getBytes(StandardCharsets.UTF_8)) : null; + QRDisplayDialog qrDisplayDialog = new DescriptorQRDisplayDialog(walletForm.getWallet().getFullDisplayName(), outputDescriptor.toString(true), cryptoOutputUR, bbqr, selectBbqrOption); qrDisplayDialog.initOwner(showDescriptorQR.getScene().getWindow()); qrDisplayDialog.showAndWait(); }