mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
optionally show output descriptor qr export as bbqr, update coldcard import and export instructions
This commit is contained in:
parent
f6ff92865b
commit
daf320f36b
10 changed files with 63 additions and 19 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit 60ac42800222a487651b93529796d31e5a954b99
|
Subproject commit 33bf35e3c4fdaed6e6b0d598efaa3f8f0406c266
|
|
@ -3,13 +3,14 @@ package com.sparrowwallet.sparrow.control;
|
||||||
import com.sparrowwallet.hummingbird.UR;
|
import com.sparrowwallet.hummingbird.UR;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import com.sparrowwallet.sparrow.io.PdfUtils;
|
import com.sparrowwallet.sparrow.io.PdfUtils;
|
||||||
|
import com.sparrowwallet.sparrow.io.bbqr.BBQR;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
||||||
public class DescriptorQRDisplayDialog extends QRDisplayDialog {
|
public class DescriptorQRDisplayDialog extends QRDisplayDialog {
|
||||||
public DescriptorQRDisplayDialog(String walletName, String outputDescriptor, UR ur) {
|
public DescriptorQRDisplayDialog(String walletName, String outputDescriptor, UR ur, BBQR bbqr, boolean selectBbqrButton) {
|
||||||
super(ur);
|
super(ur, bbqr, false, false, selectBbqrButton);
|
||||||
|
|
||||||
DialogPane dialogPane = getDialogPane();
|
DialogPane dialogPane = getDialogPane();
|
||||||
final ButtonType pdfButtonType = new javafx.scene.control.ButtonType("Save PDF...", ButtonBar.ButtonData.HELP_2);
|
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.setGraphicTextGap(5);
|
||||||
pdfButton.setGraphic(getGlyph(FontAwesome5.Glyph.FILE_PDF));
|
pdfButton.setGraphic(getGlyph(FontAwesome5.Glyph.FILE_PDF));
|
||||||
pdfButton.addEventFilter(ActionEvent.ACTION, event -> {
|
pdfButton.addEventFilter(ActionEvent.ACTION, event -> {
|
||||||
PdfUtils.saveOutputDescriptor(walletName, outputDescriptor, ur);
|
PdfUtils.saveOutputDescriptor(walletName, outputDescriptor, ur, isUseBbqrEncoding() ? bbqr : null);
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,11 +171,18 @@ public class FileWalletExportPane extends TitledDescriptionPane {
|
||||||
} else if(exporter instanceof Bip129) {
|
} else if(exporter instanceof Bip129) {
|
||||||
UR ur = UR.fromBytes(outputStream.toByteArray());
|
UR ur = UR.fromBytes(outputStream.toByteArray());
|
||||||
BBQR bbqr = new BBQR(BBQRType.UNICODE, 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) {
|
} 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);
|
OutputDescriptor outputDescriptor = OutputDescriptor.getOutputDescriptor(exportWallet, KeyPurpose.DEFAULT_PURPOSES, null);
|
||||||
CryptoOutput cryptoOutput = getCryptoOutput(exportWallet);
|
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 {
|
} else {
|
||||||
qrDisplayDialog = new QRDisplayDialog(outputStream.toString(StandardCharsets.UTF_8));
|
qrDisplayDialog = new QRDisplayDialog(outputStream.toString(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,10 @@ public class QRDisplayDialog extends Dialog<ButtonType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseBbqrEncoding() {
|
||||||
|
return useBbqrEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
private void setUseBbqrEncoding(boolean useBbqrEncoding) {
|
private void setUseBbqrEncoding(boolean useBbqrEncoding) {
|
||||||
if(useBbqrEncoding) {
|
if(useBbqrEncoding) {
|
||||||
this.useBbqrEncoding = true;
|
this.useBbqrEncoding = true;
|
||||||
|
|
|
@ -111,7 +111,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getKeystoreImportDescription(int account) {
|
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
|
@Override
|
||||||
|
@ -186,7 +186,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWalletImportDescription() {
|
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
|
@Override
|
||||||
|
@ -239,7 +239,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWalletExportDescription() {
|
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
|
@Override
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getKeystoreImportDescription(int account) {
|
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
|
@Override
|
||||||
|
|
|
@ -22,6 +22,9 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.hummingbird.UR;
|
import com.sparrowwallet.hummingbird.UR;
|
||||||
import com.sparrowwallet.hummingbird.UREncoder;
|
import com.sparrowwallet.hummingbird.UREncoder;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
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.embed.swing.SwingFXUtils;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
@ -39,7 +42,7 @@ public class PdfUtils {
|
||||||
private static final int QR_WIDTH = 480;
|
private static final int QR_WIDTH = 480;
|
||||||
private static final int QR_HEIGHT = 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();
|
Stage window = new Stage();
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
fileChooser.setTitle("Save PDF");
|
fileChooser.setTitle("Save PDF");
|
||||||
|
@ -56,9 +59,22 @@ public class PdfUtils {
|
||||||
Chunk title = new Chunk("Output descriptor for " + walletName, titleFont);
|
Chunk title = new Chunk("Output descriptor for " + walletName, titleFont);
|
||||||
document.add(title);
|
document.add(title);
|
||||||
|
|
||||||
UREncoder urEncoder = new UREncoder(ur, 2000, 10, 0);
|
String fragment = null;
|
||||||
String fragment = urEncoder.nextPart();
|
if(bbqr != null) {
|
||||||
if(urEncoder.isSinglePart()) {
|
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);
|
Image image = Image.getInstance(SwingFXUtils.fromFXImage(getQrCode(fragment), null), Color.WHITE);
|
||||||
document.add(image);
|
document.add(image);
|
||||||
}
|
}
|
||||||
|
|
|
@ -905,9 +905,9 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
toggleButton.setSelected(false);
|
toggleButton.setSelected(false);
|
||||||
|
|
||||||
//TODO: Remove once Cobo Vault support has been removed
|
//TODO: Remove once Cobo Vault support has been removed
|
||||||
boolean addLegacyEncodingOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COBO_VAULT));
|
boolean addLegacyEncodingOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().showLegacyQR());
|
||||||
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 addBbqrOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().showBbqr());
|
||||||
boolean selectBbqrOption = headersForm.getSigningWallet().getKeystores().stream().allMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COLDCARD));
|
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
|
//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());
|
boolean includeNonWitnessUtxos = !Arrays.asList(ScriptType.WITNESS_TYPES).contains(headersForm.getSigningWallet().getScriptType());
|
||||||
|
|
|
@ -5,12 +5,16 @@ import com.sparrowwallet.hummingbird.UR;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import com.sparrowwallet.sparrow.io.PdfUtils;
|
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.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import org.controlsfx.glyphfont.Glyph;
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class MultisigBackupDialog extends Dialog<String> {
|
public class MultisigBackupDialog extends Dialog<String> {
|
||||||
private final Wallet wallet;
|
private final Wallet wallet;
|
||||||
private final String descriptor;
|
private final String descriptor;
|
||||||
|
@ -71,7 +75,12 @@ public class MultisigBackupDialog extends Dialog<String> {
|
||||||
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
||||||
ButtonBar.setButtonData(pdfButton, buttonData);
|
ButtonBar.setButtonData(pdfButton, buttonData);
|
||||||
pdfButton.setOnAction(event -> {
|
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;
|
button = pdfButton;
|
||||||
|
|
|
@ -18,6 +18,8 @@ import com.sparrowwallet.sparrow.event.*;
|
||||||
import com.sparrowwallet.sparrow.io.Config;
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import com.sparrowwallet.sparrow.io.Storage;
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import com.sparrowwallet.sparrow.io.StorageException;
|
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.ElectrumServer;
|
||||||
import com.sparrowwallet.sparrow.net.ServerType;
|
import com.sparrowwallet.sparrow.net.ServerType;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
@ -37,6 +39,7 @@ import tornadofx.control.Fieldset;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -376,8 +379,12 @@ public class SettingsController extends WalletFormController implements Initiali
|
||||||
return;
|
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();
|
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.initOwner(showDescriptorQR.getScene().getWindow());
|
||||||
qrDisplayDialog.showAndWait();
|
qrDisplayDialog.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue