mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-02 20:36:44 +00:00
psbt combining, transaction viewer updating
This commit is contained in:
parent
b0f4d3b4c9
commit
ef5124a9b9
23 changed files with 333 additions and 144 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
|||
Subproject commit 70d0b7afcd6f0575bf424a45f54dd6e039057dba
|
||||
Subproject commit 0466755883c19a9e679f5e937b2f7db55a73e05b
|
|
@ -703,7 +703,15 @@ public class AppController implements Initializable {
|
|||
TabData tabData = (TabData)tab.getUserData();
|
||||
if(tabData instanceof TransactionTabData) {
|
||||
TransactionTabData transactionTabData = (TransactionTabData)tabData;
|
||||
if(transactionTabData.getTransaction().getTxId().equals(transaction.getTxId())) {
|
||||
|
||||
//If an exact match bytewise of an existing tab, return that tab
|
||||
if(Arrays.equals(transactionTabData.getTransaction().bitcoinSerialize(), transaction.bitcoinSerialize())) {
|
||||
//As per BIP174, combine PSBTs with matching transactions
|
||||
if(transactionTabData.getPsbt() != null && psbt != null) {
|
||||
transactionTabData.getPsbt().combine(psbt);
|
||||
EventManager.get().post(new PSBTCombinedEvent(transactionTabData.getPsbt()));
|
||||
}
|
||||
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
|
@ -717,7 +725,7 @@ public class AppController implements Initializable {
|
|||
}
|
||||
|
||||
Tab tab = new Tab(tabName);
|
||||
TabData tabData = new TransactionTabData(TabData.TabType.TRANSACTION, transaction);
|
||||
TabData tabData = new TransactionTabData(TabData.TabType.TRANSACTION, transaction, psbt);
|
||||
tab.setUserData(tabData);
|
||||
tab.setContextMenu(getTabContextMenu(tab));
|
||||
tab.setClosable(true);
|
||||
|
@ -733,6 +741,8 @@ public class AppController implements Initializable {
|
|||
controller.setTransaction(transaction);
|
||||
}
|
||||
|
||||
controller.setName(name);
|
||||
|
||||
if(initialView != null) {
|
||||
controller.setInitialView(initialView, initialIndex);
|
||||
}
|
||||
|
@ -919,4 +929,9 @@ public class AppController implements Initializable {
|
|||
public void requestWalletOpen(RequestWalletOpenEvent event) {
|
||||
openWallet(null);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void requestTransactionOpen(RequestTransactionOpenEvent event) {
|
||||
openTransactionFromFile(null);
|
||||
}
|
||||
}
|
|
@ -1,108 +1,37 @@
|
|||
package com.sparrowwallet.sparrow;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.Script;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptChunk;
|
||||
import com.sparrowwallet.sparrow.transaction.ScriptContextMenu;
|
||||
import com.sparrowwallet.sparrow.control.ScriptArea;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.stage.Popup;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import org.fxmisc.richtext.event.MouseOverTextEvent;
|
||||
import org.fxmisc.richtext.model.TwoDimensional;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import static com.sparrowwallet.drongo.protocol.ScriptType.*;
|
||||
import static com.sparrowwallet.drongo.protocol.ScriptType.P2WSH;
|
||||
import static org.fxmisc.richtext.model.TwoDimensional.Bias.Backward;
|
||||
|
||||
public abstract class BaseController {
|
||||
protected void appendScript(CodeArea codeArea, Script script) {
|
||||
appendScript(codeArea, script, null, null);
|
||||
}
|
||||
|
||||
protected void appendScript(CodeArea codeArea, Script script, Script redeemScript, Script witnessScript) {
|
||||
if(P2PKH.isScriptType(script)) {
|
||||
codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append(script.getChunks().get(1).toString(), "script-opcode");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append("<pkh>", "script-hash");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append(script.getChunks().get(3).toString(), "script-opcode");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append(script.getChunks().get(4).toString(), "script-opcode");
|
||||
} else if(P2SH.isScriptType(script)) {
|
||||
codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append("<sh>", "script-hash");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append(script.getChunks().get(2).toString(), "script-opcode");
|
||||
} else if(P2WPKH.isScriptType(script)) {
|
||||
codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append("<wpkh>", "script-hash");
|
||||
} else if(P2WSH.isScriptType(script)) {
|
||||
codeArea.append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
codeArea.append(" ", "");
|
||||
codeArea.append("<wsh>", "script-hash");
|
||||
} else {
|
||||
int signatureCount = 1;
|
||||
int pubKeyCount = 1;
|
||||
for (int i = 0; i < script.getChunks().size(); i++) {
|
||||
ScriptChunk chunk = script.getChunks().get(i);
|
||||
if(chunk.isOpCode()) {
|
||||
codeArea.append(chunk.toString(), "script-opcode");
|
||||
} else if(chunk.isSignature()) {
|
||||
codeArea.append("<signature" + signatureCount++ + ">", "script-signature");
|
||||
} else if(chunk.isPubKey()) {
|
||||
codeArea.append("<pubkey" + pubKeyCount++ + ">", "script-pubkey");
|
||||
} else if(chunk.isScript()) {
|
||||
Script nestedScript = chunk.getScript();
|
||||
if (nestedScript.equals(redeemScript)) {
|
||||
codeArea.append("<RedeemScript>", "script-redeem");
|
||||
} else if (nestedScript.equals(witnessScript)) {
|
||||
codeArea.append("<WitnessScript>", "script-redeem");
|
||||
} else {
|
||||
codeArea.append("(", "script-nest");
|
||||
appendScript(codeArea, nestedScript);
|
||||
codeArea.append(")", "script-nest");
|
||||
}
|
||||
} else {
|
||||
codeArea.append(chunk.toString(), "script-other");
|
||||
}
|
||||
|
||||
if(i < script.getChunks().size() - 1) {
|
||||
codeArea.append(" ", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addScriptPopup(codeArea, script);
|
||||
}
|
||||
|
||||
protected void addScriptPopup(CodeArea area, Script script) {
|
||||
ScriptContextMenu contextMenu = new ScriptContextMenu(area, script);
|
||||
area.setContextMenu(contextMenu);
|
||||
|
||||
protected void initializeScriptField(ScriptArea scriptArea) {
|
||||
Popup popup = new Popup();
|
||||
Label popupMsg = new Label();
|
||||
popupMsg.getStyleClass().add("tooltip");
|
||||
popup.getContent().add(popupMsg);
|
||||
|
||||
area.setMouseOverTextDelay(Duration.ofMillis(150));
|
||||
area.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_BEGIN, e -> {
|
||||
TwoDimensional.Position position = area.getParagraph(0).getStyleSpans().offsetToPosition(e.getCharacterIndex(), Backward);
|
||||
scriptArea.setMouseOverTextDelay(Duration.ofMillis(150));
|
||||
scriptArea.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_BEGIN, e -> {
|
||||
TwoDimensional.Position position = scriptArea.getParagraph(0).getStyleSpans().offsetToPosition(e.getCharacterIndex(), Backward);
|
||||
if(position.getMajor() % 2 == 0) {
|
||||
ScriptChunk hoverChunk = script.getChunks().get(position.getMajor()/2);
|
||||
ScriptChunk hoverChunk = scriptArea.getScript().getChunks().get(position.getMajor()/2);
|
||||
if(!hoverChunk.isOpCode()) {
|
||||
Point2D pos = e.getScreenPosition();
|
||||
popupMsg.setText(describeScriptChunk(hoverChunk));
|
||||
popup.show(area, pos.getX(), pos.getY() + 10);
|
||||
popup.show(scriptArea, pos.getX(), pos.getY() + 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
area.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_END, e -> {
|
||||
scriptArea.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_END, e -> {
|
||||
popup.hide();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,16 +1,27 @@
|
|||
package com.sparrowwallet.sparrow;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
|
||||
public class TransactionTabData extends TabData {
|
||||
private Transaction transaction;
|
||||
private final Transaction transaction;
|
||||
private final PSBT psbt;
|
||||
|
||||
public TransactionTabData(TabType type, Transaction transaction) {
|
||||
this(type, transaction, null);
|
||||
}
|
||||
|
||||
public TransactionTabData(TabType type, Transaction transaction, PSBT psbt) {
|
||||
super(type);
|
||||
this.transaction = transaction;
|
||||
this.psbt = psbt;
|
||||
}
|
||||
|
||||
public Transaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public PSBT getPsbt() {
|
||||
return psbt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.Script;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptChunk;
|
||||
import com.sparrowwallet.sparrow.transaction.ScriptContextMenu;
|
||||
import javafx.geometry.Pos;
|
||||
import org.controlsfx.control.decoration.Decorator;
|
||||
import org.controlsfx.control.decoration.GraphicDecoration;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
|
||||
import static com.sparrowwallet.drongo.protocol.ScriptType.*;
|
||||
|
||||
public class ScriptArea extends CodeArea {
|
||||
private Script script;
|
||||
|
||||
public void appendScript(Script script) {
|
||||
appendScript(script, null, null);
|
||||
}
|
||||
|
||||
public void appendScript(Script script, Script redeemScript, Script witnessScript) {
|
||||
if(this.script == null) {
|
||||
this.script = script;
|
||||
ScriptContextMenu contextMenu = new ScriptContextMenu(this, script);
|
||||
setContextMenu(contextMenu);
|
||||
}
|
||||
|
||||
if(P2PKH.isScriptType(script)) {
|
||||
append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
append(" ", "");
|
||||
append(script.getChunks().get(1).toString(), "script-opcode");
|
||||
append(" ", "");
|
||||
append("<pkh>", "script-hash");
|
||||
append(" ", "");
|
||||
append(script.getChunks().get(3).toString(), "script-opcode");
|
||||
append(" ", "");
|
||||
append(script.getChunks().get(4).toString(), "script-opcode");
|
||||
} else if(P2SH.isScriptType(script)) {
|
||||
append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
append(" ", "");
|
||||
append("<sh>", "script-hash");
|
||||
append(" ", "");
|
||||
append(script.getChunks().get(2).toString(), "script-opcode");
|
||||
} else if(P2WPKH.isScriptType(script)) {
|
||||
append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
append(" ", "");
|
||||
append("<wpkh>", "script-hash");
|
||||
} else if(P2WSH.isScriptType(script)) {
|
||||
append(script.getChunks().get(0).toString(), "script-opcode");
|
||||
append(" ", "");
|
||||
append("<wsh>", "script-hash");
|
||||
} else {
|
||||
int signatureCount = 1;
|
||||
int pubKeyCount = 1;
|
||||
for (int i = 0; i < script.getChunks().size(); i++) {
|
||||
ScriptChunk chunk = script.getChunks().get(i);
|
||||
if(chunk.isOpCode()) {
|
||||
append(chunk.toString(), "script-opcode");
|
||||
} else if(chunk.isSignature()) {
|
||||
append("<signature" + signatureCount++ + ">", "script-signature");
|
||||
} else if(chunk.isPubKey()) {
|
||||
append("<pubkey" + pubKeyCount++ + ">", "script-pubkey");
|
||||
} else if(chunk.isScript()) {
|
||||
Script nestedScript = chunk.getScript();
|
||||
if (nestedScript.equals(redeemScript)) {
|
||||
append("<RedeemScript>", "script-redeem");
|
||||
} else if(nestedScript.equals(witnessScript)) {
|
||||
append("<WitnessScript>", "script-redeem");
|
||||
} else {
|
||||
append("(", "script-nest");
|
||||
appendScript(nestedScript);
|
||||
append(")", "script-nest");
|
||||
}
|
||||
} else {
|
||||
append(chunk.toString(), "script-other");
|
||||
}
|
||||
|
||||
if(i < script.getChunks().size() - 1) {
|
||||
append(" ", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
super.clear();
|
||||
this.script = null;
|
||||
setDisable(false);
|
||||
setContextMenu(null);
|
||||
Decorator.removeAllDecorations(this);
|
||||
}
|
||||
|
||||
public void addPSBTDecoration(String description, String styleClass) {
|
||||
Decorator.addDecoration(this, new GraphicDecoration(new TextDecoration("PSBT", description, styleClass), Pos.TOP_RIGHT));
|
||||
}
|
||||
|
||||
public Script getScript() {
|
||||
return script;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
|
||||
public class PSBTCombinedEvent extends PSBTEvent {
|
||||
public PSBTCombinedEvent(PSBT psbt) {
|
||||
super(psbt);
|
||||
}
|
||||
}
|
15
src/main/java/com/sparrowwallet/sparrow/event/PSBTEvent.java
Normal file
15
src/main/java/com/sparrowwallet/sparrow/event/PSBTEvent.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
|
||||
public class PSBTEvent {
|
||||
private final PSBT psbt;
|
||||
|
||||
public PSBTEvent(PSBT psbt) {
|
||||
this.psbt = psbt;
|
||||
}
|
||||
|
||||
public PSBT getPsbt() {
|
||||
return psbt;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
public class RequestTransactionOpenEvent {
|
||||
//Empty event class used to request the transaction open dialog
|
||||
}
|
|
@ -15,6 +15,8 @@ public class FontAwesome5 extends GlyphFont {
|
|||
* The individual glyphs offered by the FontAwesome5 font.
|
||||
*/
|
||||
public static enum Glyph implements INamedCharacter {
|
||||
ARROW_UP('\uf062'),
|
||||
CAMERA('\uf030'),
|
||||
CHECK_CIRCLE('\uf058'),
|
||||
CIRCLE('\uf111'),
|
||||
COINS('\uf51e'),
|
||||
|
|
|
@ -21,6 +21,8 @@ import javafx.fxml.Initializable;
|
|||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
import tornadofx.control.DateTimePicker;
|
||||
import tornadofx.control.Field;
|
||||
|
@ -29,7 +31,10 @@ import com.google.common.eventbus.Subscribe;
|
|||
import tornadofx.control.Form;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
|
@ -434,11 +439,47 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
}
|
||||
|
||||
public void showPSBT(ActionEvent event) {
|
||||
ToggleButton toggleButton = (ToggleButton)event.getSource();
|
||||
toggleButton.setSelected(false);
|
||||
|
||||
headersForm.getSignedKeystores().add(headersForm.getSigningWallet().getKeystores().get(0));
|
||||
}
|
||||
|
||||
public void savePSBT(ActionEvent event) {
|
||||
public void scanPSBT(ActionEvent event) {
|
||||
ToggleButton toggleButton = (ToggleButton)event.getSource();
|
||||
toggleButton.setSelected(false);
|
||||
}
|
||||
|
||||
public void savePSBT(ActionEvent event) {
|
||||
ToggleButton toggleButton = (ToggleButton)event.getSource();
|
||||
toggleButton.setSelected(false);
|
||||
|
||||
Stage window = new Stage();
|
||||
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Save PSBT");
|
||||
|
||||
if(headersForm.getName() != null && !headersForm.getName().isEmpty()) {
|
||||
fileChooser.setInitialFileName(headersForm.getName() + ".psbt");
|
||||
}
|
||||
|
||||
File file = fileChooser.showSaveDialog(window);
|
||||
if(file != null) {
|
||||
try {
|
||||
try(PrintWriter writer = new PrintWriter(file, StandardCharsets.UTF_8)) {
|
||||
writer.print(headersForm.getPsbt().toBase64String());
|
||||
}
|
||||
} catch(IOException e) {
|
||||
AppController.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadPSBT(ActionEvent event) {
|
||||
ToggleButton toggleButton = (ToggleButton)event.getSource();
|
||||
toggleButton.setSelected(false);
|
||||
|
||||
EventManager.get().post(new RequestTransactionOpenEvent());
|
||||
}
|
||||
|
||||
public void signPSBT(ActionEvent event) {
|
||||
|
@ -570,4 +611,11 @@ public class HeadersController extends TransactionFormController implements Init
|
|||
signaturesForm.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void psbtCombined(PSBTCombinedEvent event) {
|
||||
if(event.getPsbt().equals(headersForm.getPsbt()) && headersForm.getSigningWallet() != null) {
|
||||
updateSignedKeystores(headersForm.getSigningWallet());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,17 +14,12 @@ import com.sparrowwallet.sparrow.event.*;
|
|||
import javafx.collections.ListChangeListener;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.Button;
|
||||
import org.controlsfx.control.ToggleSwitch;
|
||||
import org.controlsfx.control.decoration.Decorator;
|
||||
import org.controlsfx.control.decoration.GraphicDecoration;
|
||||
import org.fxmisc.flowless.VirtualizedScrollPane;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import tornadofx.control.Field;
|
||||
import tornadofx.control.Fieldset;
|
||||
import org.fxmisc.flowless.VirtualizedScrollPane;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
|
@ -60,25 +55,25 @@ public class InputController extends TransactionFormController implements Initia
|
|||
private AddressLabel address;
|
||||
|
||||
@FXML
|
||||
private CodeArea scriptSigArea;
|
||||
private ScriptArea scriptSigArea;
|
||||
|
||||
@FXML
|
||||
private VirtualizedScrollPane<CodeArea> redeemScriptScroll;
|
||||
|
||||
@FXML
|
||||
private CodeArea redeemScriptArea;
|
||||
private ScriptArea redeemScriptArea;
|
||||
|
||||
@FXML
|
||||
private VirtualizedScrollPane<CodeArea> witnessScriptScroll;
|
||||
|
||||
@FXML
|
||||
private CodeArea witnessScriptArea;
|
||||
private ScriptArea witnessScriptArea;
|
||||
|
||||
@FXML
|
||||
private VirtualizedScrollPane<CodeArea> witnessesScroll;
|
||||
|
||||
@FXML
|
||||
private CodeArea witnessesArea;
|
||||
private ScriptArea witnessesArea;
|
||||
|
||||
@FXML
|
||||
private CopyableLabel signatures;
|
||||
|
@ -130,12 +125,12 @@ public class InputController extends TransactionFormController implements Initia
|
|||
|
||||
initializeInputFields(txInput, psbtInput);
|
||||
initializeScriptFields(txInput, psbtInput);
|
||||
initializeStatusFields(txInput);
|
||||
initializeStatusFields(txInput, psbtInput);
|
||||
initializeLocktimeFields(txInput);
|
||||
|
||||
if(psbtInput != null) {
|
||||
inputForm.getSignedKeystores().addListener((ListChangeListener<Keystore>) c -> {
|
||||
updateSignatures();
|
||||
updateSignatures(inputForm.getPsbtInput());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -223,6 +218,20 @@ public class InputController extends TransactionFormController implements Initia
|
|||
}
|
||||
|
||||
private void initializeScriptFields(TransactionInput txInput, PSBTInput psbtInput) {
|
||||
initializeScriptField(scriptSigArea);
|
||||
initializeScriptField(redeemScriptArea);
|
||||
initializeScriptField(witnessesArea);
|
||||
initializeScriptField(witnessScriptArea);
|
||||
|
||||
updateScriptFields(txInput, psbtInput);
|
||||
}
|
||||
|
||||
private void updateScriptFields(TransactionInput txInput, PSBTInput psbtInput) {
|
||||
scriptSigArea.clear();
|
||||
redeemScriptArea.clear();
|
||||
witnessesArea.clear();
|
||||
witnessScriptArea.clear();
|
||||
|
||||
//TODO: While we immediately check if the referenced transaction output is P2SH, where this is not present getting the first nested script is not safe
|
||||
Script redeemScript = txInput.getScriptSig().getFirstNestedScript();
|
||||
if(redeemScript != null && inputForm.getReferencedTransactionOutput() != null) {
|
||||
|
@ -233,31 +242,27 @@ public class InputController extends TransactionFormController implements Initia
|
|||
}
|
||||
|
||||
if(redeemScript == null && psbtInput != null && psbtInput.getRedeemScript() != null) {
|
||||
addPSBTDecoration(redeemScriptArea, "PSBT Redeem Script", "non-final");
|
||||
redeemScriptArea.addPSBTDecoration("PSBT Redeem Script", "non-final");
|
||||
redeemScript = psbtInput.getRedeemScript();
|
||||
}
|
||||
if(redeemScript == null && psbtInput != null && psbtInput.getFinalScriptSig() != null) {
|
||||
addPSBTDecoration(redeemScriptArea, "PSBT Final ScriptSig", "final");
|
||||
redeemScriptArea.addPSBTDecoration("PSBT Final ScriptSig", "final");
|
||||
redeemScript = psbtInput.getFinalScriptSig().getFirstNestedScript();
|
||||
}
|
||||
|
||||
scriptSigArea.clear();
|
||||
if(txInput.getScriptSig().isEmpty() && psbtInput != null && psbtInput.getFinalScriptSig() != null) {
|
||||
appendScript(scriptSigArea, psbtInput.getFinalScriptSig(), redeemScript, null);
|
||||
addPSBTDecoration(scriptSigArea, "PSBT Final ScriptSig", "final");
|
||||
scriptSigArea.appendScript(psbtInput.getFinalScriptSig(), redeemScript, null);
|
||||
scriptSigArea.addPSBTDecoration("PSBT Final ScriptSig", "final");
|
||||
} else {
|
||||
appendScript(scriptSigArea, txInput.getScriptSig(), redeemScript, null);
|
||||
scriptSigArea.appendScript(txInput.getScriptSig(), redeemScript, null);
|
||||
}
|
||||
|
||||
redeemScriptArea.clear();
|
||||
if(redeemScript != null) {
|
||||
appendScript(redeemScriptArea, redeemScript);
|
||||
redeemScriptArea.appendScript(redeemScript);
|
||||
} else {
|
||||
redeemScriptScroll.setDisable(true);
|
||||
}
|
||||
|
||||
witnessesArea.clear();
|
||||
witnessScriptArea.clear();
|
||||
Script witnesses = null;
|
||||
Script witnessScript = null;
|
||||
|
||||
|
@ -268,36 +273,31 @@ public class InputController extends TransactionFormController implements Initia
|
|||
if(psbtInput.getFinalScriptWitness() != null) {
|
||||
witnesses = new Script(psbtInput.getFinalScriptWitness().asScriptChunks());
|
||||
witnessScript = psbtInput.getFinalScriptWitness().getWitnessScript();
|
||||
addPSBTDecoration(witnessesArea, "PSBT Final ScriptWitness", "final");
|
||||
addPSBTDecoration(witnessScriptArea, "PSBT Final ScriptWitness", "final");
|
||||
witnessesArea.addPSBTDecoration("PSBT Final ScriptWitness", "final");
|
||||
witnessScriptArea.addPSBTDecoration("PSBT Final ScriptWitness", "final");
|
||||
} else if(psbtInput.getWitnessScript() != null) {
|
||||
witnessScript = psbtInput.getWitnessScript();
|
||||
addPSBTDecoration(witnessScriptArea, "PSBT Witness Script", "non-final");
|
||||
witnessScriptArea.addPSBTDecoration("PSBT Witness Script", "non-final");
|
||||
}
|
||||
}
|
||||
|
||||
if(witnesses != null) {
|
||||
appendScript(witnessesArea, witnesses, null, witnessScript);
|
||||
witnessesArea.appendScript(witnesses, null, witnessScript);
|
||||
} else {
|
||||
witnessesScroll.setDisable(true);
|
||||
}
|
||||
|
||||
if(witnessScript != null) {
|
||||
appendScript(witnessScriptArea, witnessScript);
|
||||
witnessScriptArea.appendScript(witnessScript);
|
||||
} else {
|
||||
witnessScriptScroll.setDisable(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void addPSBTDecoration(Node target, String description, String styleClass) {
|
||||
Decorator.addDecoration(target, new GraphicDecoration(new TextDecoration("PSBT", description, styleClass), Pos.TOP_RIGHT));
|
||||
}
|
||||
private void initializeStatusFields(TransactionInput txInput, PSBTInput psbtInput) {
|
||||
updateSignatures(psbtInput);
|
||||
|
||||
private void initializeStatusFields(TransactionInput txInput) {
|
||||
Transaction transaction = inputForm.getTransaction();
|
||||
|
||||
updateSignatures();
|
||||
|
||||
rbf.setSelected(txInput.isReplaceByFeeEnabled());
|
||||
rbf.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue) {
|
||||
|
@ -323,11 +323,9 @@ public class InputController extends TransactionFormController implements Initia
|
|||
rbf.setDisable(!inputForm.isEditable());
|
||||
}
|
||||
|
||||
private void updateSignatures() {
|
||||
private void updateSignatures(PSBTInput psbtInput) {
|
||||
signatures.setText("Unknown");
|
||||
if(inputForm.getPsbtInput() != null) {
|
||||
PSBTInput psbtInput = inputForm.getPsbtInput();
|
||||
|
||||
int reqSigs = -1;
|
||||
if(psbtInput.getUtxo() != null && psbtInput.getSigningScript() != null) {
|
||||
try {
|
||||
|
@ -519,4 +517,13 @@ public class InputController extends TransactionFormController implements Initia
|
|||
locktimeRelativeCombo.setDisable(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void psbtCombined(PSBTCombinedEvent event) {
|
||||
if(event.getPsbt().equals(inputForm.getPsbt())) {
|
||||
updateSpends(inputForm.getPsbtInput().getUtxo());
|
||||
updateScriptFields(inputForm.getTransactionInput(), inputForm.getPsbtInput());
|
||||
updateSignatures(inputForm.getPsbtInput());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.sparrowwallet.sparrow.control.CoinLabel;
|
|||
import com.sparrowwallet.sparrow.control.CopyableLabel;
|
||||
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
|
||||
import com.sparrowwallet.sparrow.event.BlockTransactionFetchedEvent;
|
||||
import com.sparrowwallet.sparrow.event.PSBTCombinedEvent;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
|
@ -106,7 +107,6 @@ public class InputsController extends TransactionFormController implements Initi
|
|||
signatures.setText(foundSigs + "/?");
|
||||
}
|
||||
|
||||
|
||||
addPieData(inputsPie, outputs);
|
||||
}
|
||||
|
||||
|
@ -173,4 +173,11 @@ public class InputsController extends TransactionFormController implements Initi
|
|||
public void bitcoinUnitChanged(BitcoinUnitChangedEvent event) {
|
||||
total.refresh(event.getBitcoinUnit());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void psbtCombined(PSBTCombinedEvent event) {
|
||||
if(event.getPsbt().equals(inputsForm.getPsbt())) {
|
||||
updatePSBTInputs(inputsForm.getPsbt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.sparrowwallet.sparrow.EventManager;
|
|||
import com.sparrowwallet.sparrow.control.AddressLabel;
|
||||
import com.sparrowwallet.sparrow.control.CoinLabel;
|
||||
import com.sparrowwallet.sparrow.control.CopyableLabel;
|
||||
import com.sparrowwallet.sparrow.control.ScriptArea;
|
||||
import com.sparrowwallet.sparrow.event.BitcoinUnitChangedEvent;
|
||||
import com.sparrowwallet.sparrow.event.BlockTransactionOutputsFetchedEvent;
|
||||
import com.sparrowwallet.sparrow.event.ViewTransactionEvent;
|
||||
|
@ -54,7 +55,7 @@ public class OutputController extends TransactionFormController implements Initi
|
|||
private Hyperlink spentBy;
|
||||
|
||||
@FXML
|
||||
private CodeArea scriptPubKeyArea;
|
||||
private ScriptArea scriptPubKeyArea;
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
|
@ -92,8 +93,9 @@ public class OutputController extends TransactionFormController implements Initi
|
|||
spent.setText("Unknown");
|
||||
}
|
||||
|
||||
initializeScriptField(scriptPubKeyArea);
|
||||
scriptPubKeyArea.clear();
|
||||
appendScript(scriptPubKeyArea, txOutput.getScript(), null, null);
|
||||
scriptPubKeyArea.appendScript(txOutput.getScript(), null, null);
|
||||
}
|
||||
|
||||
private void updateSpent(List<BlockTransaction> outputTransactions) {
|
||||
|
|
|
@ -368,6 +368,10 @@ public class TransactionController implements Initializable {
|
|||
this.txdata = new TransactionData(transaction);
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.txdata.setName(name);
|
||||
}
|
||||
|
||||
public PSBT getPSBT() {
|
||||
return txdata.getPsbt();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Map;
|
|||
|
||||
public class TransactionData {
|
||||
private final Transaction transaction;
|
||||
private String name;
|
||||
private PSBT psbt;
|
||||
private BlockTransaction blockTransaction;
|
||||
private Map<Sha256Hash, BlockTransaction> inputTransactions;
|
||||
|
@ -49,6 +50,14 @@ public class TransactionData {
|
|||
return transaction;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PSBT getPsbt() {
|
||||
return psbt;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ public abstract class TransactionForm {
|
|||
return txdata.getTransaction();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return txdata.getName();
|
||||
}
|
||||
|
||||
public PSBT getPsbt() {
|
||||
return txdata.getPsbt();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.sparrowwallet.sparrow.AppController;
|
|||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.CopyableLabel;
|
||||
import com.sparrowwallet.sparrow.control.CopyableTextField;
|
||||
import com.sparrowwallet.sparrow.control.ScriptArea;
|
||||
import com.sparrowwallet.sparrow.event.ReceiveToEvent;
|
||||
import com.sparrowwallet.sparrow.event.WalletHistoryChangedEvent;
|
||||
import com.sparrowwallet.sparrow.event.WalletNodesChangedEvent;
|
||||
|
@ -53,7 +54,7 @@ public class ReceiveController extends WalletFormController implements Initializ
|
|||
private ImageView qrCode;
|
||||
|
||||
@FXML
|
||||
private CodeArea scriptPubKeyArea;
|
||||
private ScriptArea scriptPubKeyArea;
|
||||
|
||||
@FXML
|
||||
private CodeArea outputDescriptor;
|
||||
|
@ -67,7 +68,7 @@ public class ReceiveController extends WalletFormController implements Initializ
|
|||
|
||||
@Override
|
||||
public void initializeView() {
|
||||
|
||||
initializeScriptField(scriptPubKeyArea);
|
||||
}
|
||||
|
||||
public void setNodeEntry(NodeEntry nodeEntry) {
|
||||
|
@ -88,7 +89,7 @@ public class ReceiveController extends WalletFormController implements Initializ
|
|||
}
|
||||
|
||||
scriptPubKeyArea.clear();
|
||||
appendScript(scriptPubKeyArea, nodeEntry.getOutputScript(), null, null);
|
||||
scriptPubKeyArea.appendScript(nodeEntry.getOutputScript(), null, null);
|
||||
|
||||
outputDescriptor.clear();
|
||||
outputDescriptor.appendText(nodeEntry.getOutputDescriptor());
|
||||
|
|
|
@ -137,6 +137,7 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
targetBlocks.setTooltip(tooltip);
|
||||
|
||||
userFeeSet.set(false);
|
||||
revalidate(amount, amountListener);
|
||||
updateTransaction();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
-fx-padding: 10 20 10 20;
|
||||
}
|
||||
|
||||
.signatures-buttons .button {
|
||||
.signatures-buttons .segmented-button, .signatures-buttons .button, .signatures-buttons .toggle-button {
|
||||
-fx-pref-height: 75px;
|
||||
-fx-max-width: Infinity;
|
||||
}
|
||||
|
|
|
@ -171,16 +171,34 @@
|
|||
</VBox>
|
||||
<VBox>
|
||||
<HBox styleClass="signatures-buttons" spacing="20">
|
||||
<Button HBox.hgrow="ALWAYS" text="Show QR" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#showPSBT">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="QRCODE" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button HBox.hgrow="ALWAYS" text="Save PSBT" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#savePSBT">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SD_CARD" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<SegmentedButton HBox.hgrow="ALWAYS">
|
||||
<buttons>
|
||||
<ToggleButton HBox.hgrow="ALWAYS" text="Show QR" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#showPSBT">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="QRCODE" />
|
||||
</graphic>
|
||||
</ToggleButton>
|
||||
<ToggleButton HBox.hgrow="ALWAYS" text="Scan QR" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#scanPSBT">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="CAMERA" />
|
||||
</graphic>
|
||||
</ToggleButton>
|
||||
</buttons>
|
||||
</SegmentedButton>
|
||||
<SegmentedButton HBox.hgrow="ALWAYS">
|
||||
<buttons>
|
||||
<ToggleButton HBox.hgrow="ALWAYS" text="Save PSBT" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#savePSBT">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="SD_CARD" />
|
||||
</graphic>
|
||||
</ToggleButton>
|
||||
<ToggleButton HBox.hgrow="ALWAYS" text="Load PSBT" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#loadPSBT">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="ARROW_UP" />
|
||||
</graphic>
|
||||
</ToggleButton>
|
||||
</buttons>
|
||||
</SegmentedButton>
|
||||
<Button fx:id="signButton" defaultButton="true" HBox.hgrow="ALWAYS" text="Sign" contentDisplay="TOP" wrapText="true" textAlignment="CENTER" onAction="#signPSBT">
|
||||
<graphic>
|
||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="20" icon="PEN_FANCY" />
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.AddressLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch?>
|
||||
<?import com.sparrowwallet.sparrow.control.ScriptArea?>
|
||||
|
||||
<GridPane hgap="10.0" vgap="10.0" styleClass="tx-pane" stylesheets="@input.css, @transaction.css, @../script.css, @../general.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.transaction.InputController">
|
||||
<padding>
|
||||
|
@ -55,28 +56,28 @@
|
|||
<Field text="ScriptSig:">
|
||||
<VirtualizedScrollPane>
|
||||
<content>
|
||||
<CodeArea fx:id="scriptSigArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
<ScriptArea fx:id="scriptSigArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
</content>
|
||||
</VirtualizedScrollPane>
|
||||
</Field>
|
||||
<Field text="RedeemScript:">
|
||||
<VirtualizedScrollPane fx:id="redeemScriptScroll">
|
||||
<content>
|
||||
<CodeArea fx:id="redeemScriptArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
<ScriptArea fx:id="redeemScriptArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
</content>
|
||||
</VirtualizedScrollPane>
|
||||
</Field>
|
||||
<Field text="Witnesses:">
|
||||
<VirtualizedScrollPane fx:id="witnessesScroll">
|
||||
<content>
|
||||
<CodeArea fx:id="witnessesArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
<ScriptArea fx:id="witnessesArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
</content>
|
||||
</VirtualizedScrollPane>
|
||||
</Field>
|
||||
<Field text="WitnessScript:">
|
||||
<VirtualizedScrollPane fx:id="witnessScriptScroll">
|
||||
<content>
|
||||
<CodeArea fx:id="witnessScriptArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
<ScriptArea fx:id="witnessScriptArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
</content>
|
||||
</VirtualizedScrollPane>
|
||||
</Field>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.CoinLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.AddressLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.ScriptArea?>
|
||||
|
||||
<GridPane hgap="10.0" vgap="10.0" styleClass="tx-pane" stylesheets="@output.css, @transaction.css, @../script.css, @../general.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.transaction.OutputController">
|
||||
<padding>
|
||||
|
@ -50,7 +51,7 @@
|
|||
<Field text="ScriptPubKey:">
|
||||
<VirtualizedScrollPane>
|
||||
<content>
|
||||
<CodeArea fx:id="scriptPubKeyArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
<ScriptArea fx:id="scriptPubKeyArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
</content>
|
||||
</VirtualizedScrollPane>
|
||||
</Field>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
|
||||
<?import org.controlsfx.glyphfont.Glyph?>
|
||||
<?import com.sparrowwallet.sparrow.control.CopyableTextField?>
|
||||
<?import com.sparrowwallet.sparrow.control.ScriptArea?>
|
||||
|
||||
<BorderPane stylesheets="@receive.css, @wallet.css, @../script.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.wallet.ReceiveController">
|
||||
<center>
|
||||
|
@ -59,7 +60,7 @@
|
|||
<Field text="ScriptPubKey">
|
||||
<VirtualizedScrollPane>
|
||||
<content>
|
||||
<CodeArea fx:id="scriptPubKeyArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
<ScriptArea fx:id="scriptPubKeyArea" editable="false" wrapText="true" prefHeight="42" maxHeight="42" styleClass="uneditable-codearea" />
|
||||
</content>
|
||||
</VirtualizedScrollPane>
|
||||
</Field>
|
||||
|
|
Loading…
Reference in a new issue