mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-04 13:26:44 +00:00
add cobo vault support with legacy qr scanning
This commit is contained in:
parent
bf6fbebd9e
commit
8e23bd64c7
5 changed files with 179 additions and 31 deletions
|
@ -51,7 +51,7 @@ dependencies {
|
||||||
implementation('com.github.arteam:simple-json-rpc-server:1.0') {
|
implementation('com.github.arteam:simple-json-rpc-server:1.0') {
|
||||||
exclude group: 'org.slf4j'
|
exclude group: 'org.slf4j'
|
||||||
}
|
}
|
||||||
implementation('com.sparrowwallet:hummingbird:1.4')
|
implementation('com.sparrowwallet:hummingbird:1.5.2')
|
||||||
implementation('com.nativelibs4java:bridj:0.7-20140918-3') {
|
implementation('com.nativelibs4java:bridj:0.7-20140918-3') {
|
||||||
exclude group: 'com.google.android.tools', module: 'dx'
|
exclude group: 'com.google.android.tools', module: 'dx'
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
|
import com.sparrowwallet.drongo.psbt.PSBTInput;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBTParseException;
|
import com.sparrowwallet.drongo.psbt.PSBTParseException;
|
||||||
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
||||||
import com.sparrowwallet.drongo.wallet.*;
|
import com.sparrowwallet.drongo.wallet.*;
|
||||||
|
@ -1137,14 +1138,31 @@ public class AppController implements Initializable {
|
||||||
|
|
||||||
//If an exact match bytewise of an existing tab, return that tab
|
//If an exact match bytewise of an existing tab, return that tab
|
||||||
if(Arrays.equals(transactionTabData.getTransaction().bitcoinSerialize(), transaction.bitcoinSerialize())) {
|
if(Arrays.equals(transactionTabData.getTransaction().bitcoinSerialize(), transaction.bitcoinSerialize())) {
|
||||||
//As per BIP174, combine PSBTs with matching transactions so long as they are not yet finalized
|
if(transactionTabData.getPsbt() != null && psbt != null && !transactionTabData.getPsbt().isFinalized()) {
|
||||||
if(transactionTabData.getPsbt() != null && psbt != null && !transactionTabData.getPsbt().isFinalized() && !psbt.isFinalized()) {
|
if(!psbt.isFinalized()) {
|
||||||
transactionTabData.getPsbt().combine(psbt);
|
//As per BIP174, combine PSBTs with matching transactions so long as they are not yet finalized
|
||||||
if(name != null && !name.isEmpty()) {
|
transactionTabData.getPsbt().combine(psbt);
|
||||||
tab.setText(name);
|
if(name != null && !name.isEmpty()) {
|
||||||
}
|
tab.setText(name);
|
||||||
|
}
|
||||||
|
|
||||||
EventManager.get().post(new PSBTCombinedEvent(transactionTabData.getPsbt()));
|
EventManager.get().post(new PSBTCombinedEvent(transactionTabData.getPsbt()));
|
||||||
|
} else {
|
||||||
|
//If the new PSBT is finalized, copy the finalized fields to the existing unfinalized PSBT
|
||||||
|
for(int i = 0; i < transactionTabData.getPsbt().getPsbtInputs().size(); i++) {
|
||||||
|
PSBTInput existingInput = transactionTabData.getPsbt().getPsbtInputs().get(i);
|
||||||
|
PSBTInput finalizedInput = psbt.getPsbtInputs().get(i);
|
||||||
|
existingInput.setFinalScriptSig(finalizedInput.getFinalScriptSig());
|
||||||
|
existingInput.setFinalScriptWitness(finalizedInput.getFinalScriptWitness());
|
||||||
|
existingInput.clearNonFinalFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name != null && !name.isEmpty()) {
|
||||||
|
tab.setText(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventManager.get().post(new PSBTFinalizedEvent(transactionTabData.getPsbt()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tab;
|
return tab;
|
||||||
|
|
|
@ -5,20 +5,22 @@ import com.google.zxing.client.j2se.MatrixToImageConfig;
|
||||||
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
import com.google.zxing.qrcode.QRCodeWriter;
|
import com.google.zxing.qrcode.QRCodeWriter;
|
||||||
|
import com.sparrowwallet.hummingbird.LegacyUREncoder;
|
||||||
|
import com.sparrowwallet.hummingbird.registry.RegistryType;
|
||||||
import com.sparrowwallet.sparrow.AppController;
|
import com.sparrowwallet.sparrow.AppController;
|
||||||
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import com.sparrowwallet.sparrow.io.ImportException;
|
import com.sparrowwallet.sparrow.io.ImportException;
|
||||||
import com.sparrowwallet.hummingbird.UR;
|
import com.sparrowwallet.hummingbird.UR;
|
||||||
import com.sparrowwallet.hummingbird.UREncoder;
|
import com.sparrowwallet.hummingbird.UREncoder;
|
||||||
import javafx.concurrent.ScheduledService;
|
import javafx.concurrent.ScheduledService;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.scene.control.ButtonBar;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.ButtonType;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.Dialog;
|
|
||||||
import javafx.scene.control.DialogPane;
|
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
import org.controlsfx.tools.Borders;
|
import org.controlsfx.tools.Borders;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -26,30 +28,41 @@ import org.slf4j.LoggerFactory;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class QRDisplayDialog extends Dialog<UR> {
|
public class QRDisplayDialog extends Dialog<UR> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(QRDisplayDialog.class);
|
private static final Logger log = LoggerFactory.getLogger(QRDisplayDialog.class);
|
||||||
|
|
||||||
private static final int MIN_FRAGMENT_LENGTH = 10;
|
private static final int MIN_FRAGMENT_LENGTH = 10;
|
||||||
private static final int MAX_FRAGMENT_LENGTH = 100;
|
private static final int MAX_FRAGMENT_LENGTH = 100;
|
||||||
|
|
||||||
private static final int ANIMATION_PERIOD_MILLIS = 200;
|
private static final int ANIMATION_PERIOD_MILLIS = 400;
|
||||||
|
|
||||||
private final UR ur;
|
private final UR ur;
|
||||||
private final UREncoder encoder;
|
private final UREncoder encoder;
|
||||||
|
|
||||||
private final ImageView qrImageView;
|
private final ImageView qrImageView;
|
||||||
|
|
||||||
|
private AnimateQRService animateQRService;
|
||||||
private String currentPart;
|
private String currentPart;
|
||||||
|
|
||||||
public QRDisplayDialog(String type, byte[] data) throws UR.URException {
|
private boolean useLegacyEncoding;
|
||||||
this(UR.fromBytes(type, data));
|
private String[] legacyParts;
|
||||||
|
private int legacyPartIndex;
|
||||||
|
|
||||||
|
public QRDisplayDialog(String type, byte[] data, boolean addLegacyEncodingOption) throws UR.URException {
|
||||||
|
this(UR.fromBytes(type, data), addLegacyEncodingOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QRDisplayDialog(UR ur) {
|
public QRDisplayDialog(UR ur) {
|
||||||
|
this(ur, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QRDisplayDialog(UR ur, boolean addLegacyEncodingOption) {
|
||||||
this.ur = ur;
|
this.ur = ur;
|
||||||
this.encoder = new UREncoder(ur, MAX_FRAGMENT_LENGTH, MIN_FRAGMENT_LENGTH, 0);
|
this.encoder = new UREncoder(ur, MAX_FRAGMENT_LENGTH, MIN_FRAGMENT_LENGTH, 0);
|
||||||
|
|
||||||
final DialogPane dialogPane = getDialogPane();
|
final DialogPane dialogPane = new QRDisplayDialogPane();
|
||||||
|
setDialogPane(dialogPane);
|
||||||
AppController.setStageIcon(dialogPane.getScene().getWindow());
|
AppController.setStageIcon(dialogPane.getScene().getWindow());
|
||||||
|
|
||||||
StackPane stackPane = new StackPane();
|
StackPane stackPane = new StackPane();
|
||||||
|
@ -62,7 +75,7 @@ public class QRDisplayDialog extends Dialog<UR> {
|
||||||
if(encoder.isSinglePart()) {
|
if(encoder.isSinglePart()) {
|
||||||
qrImageView.setImage(getQrCode(currentPart));
|
qrImageView.setImage(getQrCode(currentPart));
|
||||||
} else {
|
} else {
|
||||||
AnimateQRService animateQRService = new AnimateQRService();
|
animateQRService = new AnimateQRService();
|
||||||
animateQRService.setPeriod(Duration.millis(ANIMATION_PERIOD_MILLIS));
|
animateQRService.setPeriod(Duration.millis(ANIMATION_PERIOD_MILLIS));
|
||||||
animateQRService.start();
|
animateQRService.start();
|
||||||
setOnCloseRequest(event -> {
|
setOnCloseRequest(event -> {
|
||||||
|
@ -71,7 +84,13 @@ public class QRDisplayDialog extends Dialog<UR> {
|
||||||
}
|
}
|
||||||
|
|
||||||
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||||
dialogPane.getButtonTypes().addAll(cancelButtonType);
|
dialogPane.getButtonTypes().add(cancelButtonType);
|
||||||
|
|
||||||
|
if(addLegacyEncodingOption) {
|
||||||
|
final ButtonType legacyEncodingButtonType = new javafx.scene.control.ButtonType("Use Legacy Encoding (Cobo Vault)", ButtonBar.ButtonData.LEFT);
|
||||||
|
dialogPane.getButtonTypes().add(legacyEncodingButtonType);
|
||||||
|
}
|
||||||
|
|
||||||
dialogPane.setPrefWidth(500);
|
dialogPane.setPrefWidth(500);
|
||||||
dialogPane.setPrefHeight(550);
|
dialogPane.setPrefHeight(550);
|
||||||
|
|
||||||
|
@ -101,8 +120,16 @@ public class QRDisplayDialog extends Dialog<UR> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nextPart() {
|
private void nextPart() {
|
||||||
String fragment = encoder.nextPart();
|
if(!useLegacyEncoding) {
|
||||||
currentPart = fragment.toUpperCase();
|
String fragment = encoder.nextPart();
|
||||||
|
currentPart = fragment.toUpperCase();
|
||||||
|
} else {
|
||||||
|
currentPart = legacyParts[legacyPartIndex];
|
||||||
|
legacyPartIndex++;
|
||||||
|
if(legacyPartIndex > legacyParts.length - 1) {
|
||||||
|
legacyPartIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Image getQrCode(String fragment) {
|
private Image getQrCode(String fragment) {
|
||||||
|
@ -122,6 +149,44 @@ public class QRDisplayDialog extends Dialog<UR> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setUseLegacyEncoding(boolean useLegacyEncoding) {
|
||||||
|
if(useLegacyEncoding) {
|
||||||
|
try {
|
||||||
|
//Force to be bytes type for legacy encoding
|
||||||
|
LegacyUREncoder legacyEncoder = new LegacyUREncoder(new UR(RegistryType.BYTES.toString(), ur.getCborBytes()));
|
||||||
|
this.legacyParts = legacyEncoder.encode();
|
||||||
|
this.useLegacyEncoding = true;
|
||||||
|
|
||||||
|
if(legacyParts.length == 1) {
|
||||||
|
if(animateQRService != null) {
|
||||||
|
animateQRService.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPart();
|
||||||
|
qrImageView.setImage(getQrCode(currentPart));
|
||||||
|
} else if(!animateQRService.isRunning()) {
|
||||||
|
animateQRService.reset();
|
||||||
|
animateQRService.start();
|
||||||
|
}
|
||||||
|
} catch(UR.InvalidTypeException e) {
|
||||||
|
//Can't happen
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.useLegacyEncoding = false;
|
||||||
|
|
||||||
|
if(encoder.isSinglePart()) {
|
||||||
|
if(animateQRService != null) {
|
||||||
|
animateQRService.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
qrImageView.setImage(getQrCode(currentPart));
|
||||||
|
} else if(!animateQRService.isRunning()) {
|
||||||
|
animateQRService.reset();
|
||||||
|
animateQRService.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class AnimateQRService extends ScheduledService<Boolean> {
|
private class AnimateQRService extends ScheduledService<Boolean> {
|
||||||
@Override
|
@Override
|
||||||
protected Task<Boolean> createTask() {
|
protected Task<Boolean> createTask() {
|
||||||
|
@ -136,4 +201,44 @@ public class QRDisplayDialog extends Dialog<UR> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class QRDisplayDialogPane extends DialogPane {
|
||||||
|
@Override
|
||||||
|
protected Node createButton(ButtonType buttonType) {
|
||||||
|
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
|
||||||
|
ToggleButton legacy = new ToggleButton(buttonType.getText());
|
||||||
|
legacy.setGraphicTextGap(5);
|
||||||
|
setLegacyGraphic(legacy, false);
|
||||||
|
|
||||||
|
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
||||||
|
ButtonBar.setButtonData(legacy, buttonData);
|
||||||
|
legacy.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
setUseLegacyEncoding(newValue);
|
||||||
|
setLegacyGraphic(legacy, newValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
return legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.createButton(buttonType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLegacyGraphic(ToggleButton legacy, boolean useLegacyEncoding) {
|
||||||
|
if(useLegacyEncoding) {
|
||||||
|
legacy.setGraphic(getGlyph(FontAwesome5.Glyph.CHECK_CIRCLE, "success"));
|
||||||
|
} else {
|
||||||
|
legacy.setGraphic(getGlyph(FontAwesome5.Glyph.QUESTION_CIRCLE, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Glyph getGlyph(FontAwesome5.Glyph glyphName, String styleClass) {
|
||||||
|
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, glyphName);
|
||||||
|
glyph.setFontSize(12);
|
||||||
|
if(styleClass != null) {
|
||||||
|
glyph.getStyleClass().add(styleClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
import com.sparrowwallet.hummingbird.LegacyURDecoder;
|
||||||
import com.sparrowwallet.hummingbird.registry.*;
|
import com.sparrowwallet.hummingbird.registry.*;
|
||||||
import com.sparrowwallet.sparrow.AppController;
|
import com.sparrowwallet.sparrow.AppController;
|
||||||
import com.sparrowwallet.hummingbird.ResultType;
|
import com.sparrowwallet.hummingbird.ResultType;
|
||||||
|
@ -39,10 +40,12 @@ import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(QRScanDialog.class);
|
private static final Logger log = LoggerFactory.getLogger(QRScanDialog.class);
|
||||||
|
|
||||||
private final URDecoder decoder;
|
private final URDecoder decoder;
|
||||||
|
private final LegacyURDecoder legacyDecoder;
|
||||||
private final WebcamService webcamService;
|
private final WebcamService webcamService;
|
||||||
private List<String> parts;
|
private List<String> parts;
|
||||||
|
|
||||||
|
@ -53,6 +56,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
public QRScanDialog() {
|
public QRScanDialog() {
|
||||||
this.decoder = new URDecoder();
|
this.decoder = new URDecoder();
|
||||||
|
this.legacyDecoder = new LegacyURDecoder();
|
||||||
|
|
||||||
this.webcamService = new WebcamService(WebcamResolution.VGA);
|
this.webcamService = new WebcamService(WebcamResolution.VGA);
|
||||||
WebcamView webcamView = new WebcamView(webcamService);
|
WebcamView webcamView = new WebcamView(webcamService);
|
||||||
|
@ -95,14 +99,28 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
if(isUr || qrtext.toLowerCase().startsWith(UR.UR_PREFIX)) {
|
if(isUr || qrtext.toLowerCase().startsWith(UR.UR_PREFIX)) {
|
||||||
isUr = true;
|
isUr = true;
|
||||||
decoder.receivePart(qrtext);
|
|
||||||
|
|
||||||
if(decoder.getResult() != null) {
|
if(LegacyURDecoder.isLegacyURFragment(qrtext)) {
|
||||||
URDecoder.Result urResult = decoder.getResult();
|
legacyDecoder.receivePart(qrtext.toLowerCase());
|
||||||
if(urResult.type == ResultType.SUCCESS) {
|
|
||||||
result = extractResultFromUR(urResult.ur);
|
if(legacyDecoder.isComplete()) {
|
||||||
} else {
|
try {
|
||||||
result = new Result(new URException(urResult.error));
|
UR ur = legacyDecoder.decode();
|
||||||
|
result = extractResultFromUR(ur);
|
||||||
|
} catch(Exception e) {
|
||||||
|
result = new Result(new URException(e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
decoder.receivePart(qrtext);
|
||||||
|
|
||||||
|
if(decoder.getResult() != null) {
|
||||||
|
URDecoder.Result urResult = decoder.getResult();
|
||||||
|
if(urResult.type == ResultType.SUCCESS) {
|
||||||
|
result = extractResultFromUR(urResult.ur);
|
||||||
|
} else {
|
||||||
|
result = new Result(new URException(urResult.error));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(partMatcher.matches()) {
|
} else if(partMatcher.matches()) {
|
||||||
|
@ -313,8 +331,8 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
lastChild = new ChildNumber(lastComponent.getIndex(), lastComponent.isHardened());
|
lastChild = new ChildNumber(lastComponent.getIndex(), lastComponent.isHardened());
|
||||||
depth = cryptoHDKey.getOrigin().getComponents().size();
|
depth = cryptoHDKey.getOrigin().getComponents().size();
|
||||||
}
|
}
|
||||||
if(cryptoHDKey.getOrigin().getParentFingerprint() != null) {
|
if(cryptoHDKey.getParentFingerprint() != null) {
|
||||||
parentFingerprint = cryptoHDKey.getOrigin().getParentFingerprint();
|
parentFingerprint = cryptoHDKey.getParentFingerprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DeterministicKey pubKey = new DeterministicKey(List.of(lastChild), cryptoHDKey.getChainCode(), cryptoHDKey.getKey(), depth, parentFingerprint);
|
DeterministicKey pubKey = new DeterministicKey(List.of(lastChild), cryptoHDKey.getChainCode(), cryptoHDKey.getKey(), depth, parentFingerprint);
|
||||||
|
@ -387,7 +405,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
private KeyDerivation getKeyDerivation(CryptoKeypath cryptoKeypath) {
|
private KeyDerivation getKeyDerivation(CryptoKeypath cryptoKeypath) {
|
||||||
if(cryptoKeypath != null) {
|
if(cryptoKeypath != null) {
|
||||||
return new KeyDerivation(Utils.bytesToHex(cryptoKeypath.getParentFingerprint()), cryptoKeypath.getPath());
|
return new KeyDerivation(Utils.bytesToHex(cryptoKeypath.getSourceFingerprint()), cryptoKeypath.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -620,8 +620,11 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
ToggleButton toggleButton = (ToggleButton)event.getSource();
|
ToggleButton toggleButton = (ToggleButton)event.getSource();
|
||||||
toggleButton.setSelected(false);
|
toggleButton.setSelected(false);
|
||||||
|
|
||||||
|
//TODO: Remove once Cobo Vault has upgraded to UR2.0
|
||||||
|
boolean addLegacyEncodingOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COBO_VAULT));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
QRDisplayDialog qrDisplayDialog = new QRDisplayDialog(RegistryType.CRYPTO_PSBT.toString(), headersForm.getPsbt().serialize());
|
QRDisplayDialog qrDisplayDialog = new QRDisplayDialog(RegistryType.CRYPTO_PSBT.toString(), headersForm.getPsbt().serialize(), addLegacyEncodingOption);
|
||||||
qrDisplayDialog.show();
|
qrDisplayDialog.show();
|
||||||
} catch(UR.URException e) {
|
} catch(UR.URException e) {
|
||||||
log.error("Error creating PSBT UR", e);
|
log.error("Error creating PSBT UR", e);
|
||||||
|
@ -981,6 +984,10 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void psbtFinalized(PSBTFinalizedEvent event) {
|
public void psbtFinalized(PSBTFinalizedEvent event) {
|
||||||
if(event.getPsbt().equals(headersForm.getPsbt())) {
|
if(event.getPsbt().equals(headersForm.getPsbt())) {
|
||||||
|
if(headersForm.getSigningWallet() != null) {
|
||||||
|
updateSignedKeystores(headersForm.getSigningWallet());
|
||||||
|
}
|
||||||
|
|
||||||
signButtonBox.setVisible(false);
|
signButtonBox.setVisible(false);
|
||||||
broadcastButtonBox.setVisible(true);
|
broadcastButtonBox.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue