optionally show output descriptor qr export as bbqr, update coldcard import and export instructions

This commit is contained in:
Craig Raw 2024-05-09 12:20:54 +02:00
parent f6ff92865b
commit daf320f36b
10 changed files with 63 additions and 19 deletions

2
drongo

@ -1 +1 @@
Subproject commit 60ac42800222a487651b93529796d31e5a954b99
Subproject commit 33bf35e3c4fdaed6e6b0d598efaa3f8f0406c266

View file

@ -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();
});
}

View file

@ -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));
}

View file

@ -259,6 +259,10 @@ public class QRDisplayDialog extends Dialog<ButtonType> {
}
}
public boolean isUseBbqrEncoding() {
return useBbqrEncoding;
}
private void setUseBbqrEncoding(boolean useBbqrEncoding) {
if(useBbqrEncoding) {
this.useBbqrEncoding = true;

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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());

View file

@ -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<String> {
private final Wallet wallet;
private final String descriptor;
@ -71,7 +75,12 @@ public class MultisigBackupDialog extends Dialog<String> {
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;

View file

@ -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();
}