mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2025-11-05 11:56:37 +00:00
WIP - testnet support
This commit is contained in:
parent
2cb667a671
commit
4c94e52ef7
19 changed files with 98 additions and 42 deletions
2
drongo
2
drongo
|
|
@ -1 +1 @@
|
||||||
Subproject commit e8d8fa61268ec8ac4dd5c14e6715d4a4bde2fe49
|
Subproject commit 6d156505587bbbcddb5bea001cf21fbe6195e863
|
||||||
|
|
@ -9,6 +9,7 @@ import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
|
import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
|
||||||
import com.sparrowwallet.drongo.crypto.Key;
|
import com.sparrowwallet.drongo.crypto.Key;
|
||||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
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;
|
||||||
|
|
@ -551,7 +552,8 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openTransactionFromQR(ActionEvent event) {
|
public void openTransactionFromQR(ActionEvent event) {
|
||||||
QRScanDialog qrScanDialog = new QRScanDialog();
|
//TODO: is wallet always valid???
|
||||||
|
QRScanDialog qrScanDialog = new QRScanDialog(getWalletForCurrentTab().getNetwork());
|
||||||
Optional<QRScanDialog.Result> optionalResult = qrScanDialog.showAndWait();
|
Optional<QRScanDialog.Result> optionalResult = qrScanDialog.showAndWait();
|
||||||
if(optionalResult.isPresent()) {
|
if(optionalResult.isPresent()) {
|
||||||
QRScanDialog.Result result = optionalResult.get();
|
QRScanDialog.Result result = optionalResult.get();
|
||||||
|
|
@ -746,7 +748,8 @@ public class AppController implements Initializable {
|
||||||
if(walletName.isPresent()) {
|
if(walletName.isPresent()) {
|
||||||
File walletFile = Storage.getWalletFile(walletName.get());
|
File walletFile = Storage.getWalletFile(walletName.get());
|
||||||
Storage storage = new Storage(walletFile);
|
Storage storage = new Storage(walletFile);
|
||||||
Wallet wallet = new Wallet(walletName.get(), PolicyType.SINGLE, ScriptType.P2WPKH);
|
//TODO: get from settings or user input
|
||||||
|
Wallet wallet = new Wallet(Network.BITCOIN, walletName.get(), PolicyType.SINGLE, ScriptType.P2WPKH);
|
||||||
Tab tab = addWalletTab(storage, wallet);
|
Tab tab = addWalletTab(storage, wallet);
|
||||||
tabs.getSelectionModel().select(tab);
|
tabs.getSelectionModel().select(tab);
|
||||||
}
|
}
|
||||||
|
|
@ -911,18 +914,23 @@ public class AppController implements Initializable {
|
||||||
PreferencesDialog preferencesDialog = new PreferencesDialog();
|
PreferencesDialog preferencesDialog = new PreferencesDialog();
|
||||||
preferencesDialog.showAndWait();
|
preferencesDialog.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void signVerifyMessage(ActionEvent event) {
|
public Wallet getWalletForCurrentTab() {
|
||||||
MessageSignDialog messageSignDialog = null;
|
|
||||||
Tab tab = tabs.getSelectionModel().getSelectedItem();
|
Tab tab = tabs.getSelectionModel().getSelectedItem();
|
||||||
if(tab != null && tab.getUserData() instanceof WalletTabData) {
|
if(tab != null && tab.getUserData() instanceof WalletTabData) {
|
||||||
WalletTabData walletTabData = (WalletTabData)tab.getUserData();
|
WalletTabData walletTabData = (WalletTabData)tab.getUserData();
|
||||||
Wallet wallet = walletTabData.getWallet();
|
return walletTabData.getWallet();
|
||||||
if(wallet.getKeystores().size() == 1 &&
|
}
|
||||||
(wallet.getKeystores().get(0).hasSeed() || wallet.getKeystores().get(0).getSource() == KeystoreSource.HW_USB)) {
|
return null;
|
||||||
//Can sign and verify
|
}
|
||||||
messageSignDialog = new MessageSignDialog(wallet);
|
|
||||||
}
|
public void signVerifyMessage(ActionEvent event) {
|
||||||
|
MessageSignDialog messageSignDialog = null;
|
||||||
|
Wallet wallet = getWalletForCurrentTab();
|
||||||
|
if(wallet != null && wallet.getKeystores().size() == 1 &&
|
||||||
|
(wallet.getKeystores().get(0).hasSeed() || wallet.getKeystores().get(0).getSource() == KeystoreSource.HW_USB)) {
|
||||||
|
//Can sign and verify
|
||||||
|
messageSignDialog = new MessageSignDialog(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(messageSignDialog == null) {
|
if(messageSignDialog == null) {
|
||||||
|
|
@ -1001,7 +1009,9 @@ public class AppController implements Initializable {
|
||||||
|
|
||||||
private Tab addTransactionTab(String name, byte[] bytes) throws PSBTParseException, ParseException, TransactionParseException {
|
private Tab addTransactionTab(String name, byte[] bytes) throws PSBTParseException, ParseException, TransactionParseException {
|
||||||
if(PSBT.isPSBT(bytes)) {
|
if(PSBT.isPSBT(bytes)) {
|
||||||
PSBT psbt = new PSBT(bytes);
|
//TODO: test this is called from a wallet tab
|
||||||
|
Wallet wallet = getWalletForCurrentTab();
|
||||||
|
PSBT psbt = new PSBT(wallet.getNetwork(), bytes);
|
||||||
return addTransactionTab(name, psbt);
|
return addTransactionTab(name, psbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.google.common.io.ByteStreams;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import com.sparrowwallet.drongo.policy.Policy;
|
import com.sparrowwallet.drongo.policy.Policy;
|
||||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
|
@ -57,7 +58,8 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
|
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
|
||||||
Keystore keystore = importer.getKeystore(scriptType, bais, "");
|
Keystore keystore = importer.getKeystore(scriptType, bais, "");
|
||||||
|
|
||||||
Wallet wallet = new Wallet();
|
//TODO: use user input here
|
||||||
|
Wallet wallet = new Wallet(Network.BITCOIN);
|
||||||
wallet.setName(fileName);
|
wallet.setName(fileName);
|
||||||
wallet.setPolicyType(PolicyType.SINGLE);
|
wallet.setPolicyType(PolicyType.SINGLE);
|
||||||
wallet.setScriptType(scriptType);
|
wallet.setScriptType(scriptType);
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,8 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address getAddress()throws InvalidAddressException {
|
private Address getAddress()throws InvalidAddressException {
|
||||||
return Address.fromString(address.getText());
|
//TODO: is wallet always valid???
|
||||||
|
return Address.fromString(wallet.getNetwork(), address.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidAddress() {
|
private boolean isValidAddress() {
|
||||||
|
|
@ -298,7 +299,8 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
|
||||||
throw new IllegalArgumentException("Only single signature P2PKH, P2SH-P2WPKH or P2WPKH addresses can verify messages.");
|
throw new IllegalArgumentException("Only single signature P2PKH, P2SH-P2WPKH or P2WPKH addresses can verify messages.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Address signedMessageAddress = scriptType.getAddress(signedMessageKey);
|
//TODO: wallet is not always valid!!!
|
||||||
|
Address signedMessageAddress = scriptType.getAddress(wallet.getNetwork(), signedMessageKey);
|
||||||
return providedAddress.equals(signedMessageAddress);
|
return providedAddress.equals(signedMessageAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.drongo.address.Address;
|
import com.sparrowwallet.drongo.address.Address;
|
||||||
import com.sparrowwallet.drongo.protocol.Base43;
|
import com.sparrowwallet.drongo.protocol.Base43;
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
||||||
import com.sparrowwallet.sparrow.AppController;
|
import com.sparrowwallet.sparrow.AppController;
|
||||||
|
|
@ -22,13 +23,15 @@ import javafx.scene.layout.StackPane;
|
||||||
import org.controlsfx.tools.Borders;
|
import org.controlsfx.tools.Borders;
|
||||||
|
|
||||||
public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
private final Network network;
|
||||||
private final URDecoder decoder;
|
private final URDecoder decoder;
|
||||||
private final WebcamService webcamService;
|
private final WebcamService webcamService;
|
||||||
|
|
||||||
private boolean isUr;
|
private boolean isUr;
|
||||||
private QRScanDialog.Result result;
|
private QRScanDialog.Result result;
|
||||||
|
|
||||||
public QRScanDialog() {
|
public QRScanDialog(Network network) {
|
||||||
|
this.network = network;
|
||||||
this.decoder = new URDecoder();
|
this.decoder = new URDecoder();
|
||||||
|
|
||||||
this.webcamService = new WebcamService(WebcamResolution.VGA);
|
this.webcamService = new WebcamService(WebcamResolution.VGA);
|
||||||
|
|
@ -78,7 +81,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
//TODO: Confirm once UR type registry is updated
|
//TODO: Confirm once UR type registry is updated
|
||||||
if(urResult.ur.getType().contains(UR.BYTES_TYPE) || urResult.ur.getType().equals(UR.CRYPTO_PSBT_TYPE)) {
|
if(urResult.ur.getType().contains(UR.BYTES_TYPE) || urResult.ur.getType().equals(UR.CRYPTO_PSBT_TYPE)) {
|
||||||
try {
|
try {
|
||||||
PSBT psbt = new PSBT(urResult.ur.toBytes());
|
PSBT psbt = new PSBT(network, urResult.ur.toBytes());
|
||||||
result = new Result(psbt);
|
result = new Result(psbt);
|
||||||
return;
|
return;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
|
@ -107,7 +110,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
BitcoinURI bitcoinURI;
|
BitcoinURI bitcoinURI;
|
||||||
Address address;
|
Address address;
|
||||||
try {
|
try {
|
||||||
bitcoinURI = new BitcoinURI(qrtext);
|
bitcoinURI = new BitcoinURI(network, qrtext);
|
||||||
result = new Result(bitcoinURI);
|
result = new Result(bitcoinURI);
|
||||||
return;
|
return;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
|
@ -115,15 +118,15 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
address = Address.fromString(qrtext);
|
address = Address.fromString(network, qrtext);
|
||||||
result = new Result(address);
|
result = new Result(network, address);
|
||||||
return;
|
return;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
//Ignore, not an address
|
//Ignore, not an address
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
psbt = PSBT.fromString(qrtext);
|
psbt = PSBT.fromString(network, qrtext);
|
||||||
result = new Result(psbt);
|
result = new Result(psbt);
|
||||||
return;
|
return;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
|
@ -131,7 +134,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
psbt = new PSBT(qrResult.getRawBytes());
|
psbt = new PSBT(network, qrResult.getRawBytes());
|
||||||
result = new Result(psbt);
|
result = new Result(psbt);
|
||||||
return;
|
return;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
|
@ -156,7 +159,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
//Try Base43 used by Electrum
|
//Try Base43 used by Electrum
|
||||||
try {
|
try {
|
||||||
psbt = new PSBT(Base43.decode(qrResult.getText()));
|
psbt = new PSBT(network, Base43.decode(qrResult.getText()));
|
||||||
result = new Result(psbt);
|
result = new Result(psbt);
|
||||||
return;
|
return;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
|
@ -207,10 +210,10 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
this.exception = null;
|
this.exception = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result(Address address) {
|
public Result(Network network, Address address) {
|
||||||
this.transaction = null;
|
this.transaction = null;
|
||||||
this.psbt = null;
|
this.psbt = null;
|
||||||
this.uri = BitcoinURI.fromAddress(address);
|
this.uri = BitcoinURI.fromAddress(network, address);
|
||||||
this.error = null;
|
this.error = null;
|
||||||
this.exception = null;
|
this.exception = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@ public class SettingsChangedEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
POLICY, SCRIPT_TYPE, MUTLISIG_THRESHOLD, MULTISIG_TOTAL, KEYSTORE_LABEL, KEYSTORE_FINGERPRINT, KEYSTORE_DERIVATION, KEYSTORE_XPUB, GAP_LIMIT;
|
NETWORK, POLICY, SCRIPT_TYPE, MUTLISIG_THRESHOLD, MULTISIG_TOTAL, KEYSTORE_LABEL, KEYSTORE_FINGERPRINT, KEYSTORE_DERIVATION, KEYSTORE_XPUB, GAP_LIMIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.Utils;
|
import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.drongo.policy.Policy;
|
import com.sparrowwallet.drongo.policy.Policy;
|
||||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||||
|
|
@ -78,7 +79,8 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
|
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
|
||||||
Wallet wallet = new Wallet();
|
//TODO: get from settings or user input
|
||||||
|
Wallet wallet = new Wallet(Network.BITCOIN);
|
||||||
wallet.setPolicyType(PolicyType.MULTI);
|
wallet.setPolicyType(PolicyType.MULTI);
|
||||||
|
|
||||||
int threshold = 2;
|
int threshold = 2;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import com.sparrowwallet.drongo.BitcoinUnit;
|
import com.sparrowwallet.drongo.BitcoinUnit;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.sparrow.Mode;
|
import com.sparrowwallet.sparrow.Mode;
|
||||||
import com.sparrowwallet.sparrow.Theme;
|
import com.sparrowwallet.sparrow.Theme;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
@ -17,6 +18,7 @@ public class Config {
|
||||||
|
|
||||||
public static final String CONFIG_FILENAME = "config";
|
public static final String CONFIG_FILENAME = "config";
|
||||||
|
|
||||||
|
private Network network = Network.BITCOIN;
|
||||||
private Mode mode;
|
private Mode mode;
|
||||||
private BitcoinUnit bitcoinUnit;
|
private BitcoinUnit bitcoinUnit;
|
||||||
private Currency fiatCurrency;
|
private Currency fiatCurrency;
|
||||||
|
|
@ -74,6 +76,10 @@ public class Config {
|
||||||
|
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Network getNetwork() {
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
|
||||||
public Mode getMode() {
|
public Mode getMode() {
|
||||||
return mode;
|
return mode;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.drongo.crypto.*;
|
import com.sparrowwallet.drongo.crypto.*;
|
||||||
import com.sparrowwallet.drongo.policy.Policy;
|
import com.sparrowwallet.drongo.policy.Policy;
|
||||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
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;
|
||||||
|
|
@ -117,7 +118,8 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Wallet wallet = new Wallet();
|
//TODO: get from settings or user input
|
||||||
|
Wallet wallet = new Wallet(Network.BITCOIN);
|
||||||
ScriptType scriptType = null;
|
ScriptType scriptType = null;
|
||||||
|
|
||||||
for(ElectrumKeystore ek : ew.keystores.values()) {
|
for(ElectrumKeystore ek : ew.keystores.values()) {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,8 @@ public class Hwi {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getXpub(Device device, String passphrase, String derivationPath) throws ImportException {
|
public String getXpub(Device device, String passphrase, String derivationPath) throws ImportException {
|
||||||
|
//TODO: use --testnet if using testnet
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String output;
|
String output;
|
||||||
if(passphrase != null && !passphrase.isEmpty() && device.getModel().externalPassphraseEntry()) {
|
if(passphrase != null && !passphrase.isEmpty() && device.getModel().externalPassphraseEntry()) {
|
||||||
|
|
@ -91,6 +93,7 @@ public class Hwi {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String displayAddress(Device device, String passphrase, ScriptType scriptType, String derivationPath) throws DisplayAddressException {
|
public String displayAddress(Device device, String passphrase, ScriptType scriptType, String derivationPath) throws DisplayAddressException {
|
||||||
|
//TODO: use --testnet if using testnet
|
||||||
try {
|
try {
|
||||||
if(!List.of(ScriptType.P2PKH, ScriptType.P2SH_P2WPKH, ScriptType.P2WPKH).contains(scriptType)) {
|
if(!List.of(ScriptType.P2PKH, ScriptType.P2SH_P2WPKH, ScriptType.P2WPKH).contains(scriptType)) {
|
||||||
throw new IllegalArgumentException("Cannot display address for script type " + scriptType + ": Only single sig types supported");
|
throw new IllegalArgumentException("Cannot display address for script type " + scriptType + ": Only single sig types supported");
|
||||||
|
|
@ -169,7 +172,7 @@ public class Hwi {
|
||||||
JsonObject result = JsonParser.parseString(output).getAsJsonObject();
|
JsonObject result = JsonParser.parseString(output).getAsJsonObject();
|
||||||
if(result.get("psbt") != null) {
|
if(result.get("psbt") != null) {
|
||||||
String strPsbt = result.get("psbt").getAsString();
|
String strPsbt = result.get("psbt").getAsString();
|
||||||
return PSBT.fromString(strPsbt);
|
return PSBT.fromString(psbt.getNetwork(), strPsbt);
|
||||||
} else {
|
} else {
|
||||||
JsonElement error = result.get("error");
|
JsonElement error = result.get("error");
|
||||||
if(error != null && error.getAsString().equals("sign_tx canceled")) {
|
if(error != null && error.getAsString().equals("sign_tx canceled")) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.io;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.sparrowwallet.drongo.OutputDescriptor;
|
import com.sparrowwallet.drongo.OutputDescriptor;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||||
|
|
||||||
|
|
@ -53,7 +54,8 @@ public class Specter implements WalletImport, WalletExport {
|
||||||
SpecterWallet specterWallet = gson.fromJson(new InputStreamReader(inputStream), SpecterWallet.class);
|
SpecterWallet specterWallet = gson.fromJson(new InputStreamReader(inputStream), SpecterWallet.class);
|
||||||
|
|
||||||
if(specterWallet.descriptor != null) {
|
if(specterWallet.descriptor != null) {
|
||||||
OutputDescriptor outputDescriptor = OutputDescriptor.getOutputDescriptor(specterWallet.descriptor);
|
//TODO: get from settings or user input
|
||||||
|
OutputDescriptor outputDescriptor = OutputDescriptor.getOutputDescriptor(Network.BITCOIN, specterWallet.descriptor);
|
||||||
Wallet wallet = outputDescriptor.toWallet();
|
Wallet wallet = outputDescriptor.toWallet();
|
||||||
wallet.setName(specterWallet.label);
|
wallet.setName(specterWallet.label);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.google.gson.Gson;
|
||||||
import com.sparrowwallet.drongo.address.Address;
|
import com.sparrowwallet.drongo.address.Address;
|
||||||
import com.sparrowwallet.drongo.address.InvalidAddressException;
|
import com.sparrowwallet.drongo.address.InvalidAddressException;
|
||||||
import com.sparrowwallet.drongo.crypto.ECKey;
|
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.sparrow.MainApp;
|
import com.sparrowwallet.sparrow.MainApp;
|
||||||
import com.sparrowwallet.sparrow.event.VersionUpdatedEvent;
|
import com.sparrowwallet.sparrow.event.VersionUpdatedEvent;
|
||||||
|
|
@ -61,8 +62,8 @@ public class VersionCheckService extends ScheduledService<VersionUpdatedEvent> {
|
||||||
|
|
||||||
String signature = versionCheck.signatures.get(addressString);
|
String signature = versionCheck.signatures.get(addressString);
|
||||||
ECKey signedMessageKey = ECKey.signedMessageToKey(versionCheck.version, signature, false);
|
ECKey signedMessageKey = ECKey.signedMessageToKey(versionCheck.version, signature, false);
|
||||||
Address providedAddress = Address.fromString(addressString);
|
Address providedAddress = Address.fromString(Network.BITCOIN, addressString);
|
||||||
Address signedMessageAddress = ScriptType.P2PKH.getAddress(signedMessageKey);
|
Address signedMessageAddress = ScriptType.P2PKH.getAddress(Network.BITCOIN, signedMessageKey);
|
||||||
|
|
||||||
if(providedAddress.equals(signedMessageAddress)) {
|
if(providedAddress.equals(signedMessageAddress)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -870,7 +870,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
if(headersForm.getPsbt().isSigned()) {
|
if(headersForm.getPsbt().isSigned()) {
|
||||||
if(headersForm.getSigningWallet() == null) {
|
if(headersForm.getSigningWallet() == null) {
|
||||||
//As no signing wallet is available, but we want to show the PSBT has been signed and automatically finalize it, construct a special wallet with default named keystores
|
//As no signing wallet is available, but we want to show the PSBT has been signed and automatically finalize it, construct a special wallet with default named keystores
|
||||||
Wallet signedWallet = new FinalizingPSBTWallet(headersForm.getPsbt());
|
Wallet signedWallet = new FinalizingPSBTWallet(getTransactionForm().getSigningWallet().getNetwork(), headersForm.getPsbt());
|
||||||
headersForm.setSigningWallet(signedWallet);
|
headersForm.setSigningWallet(signedWallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -920,7 +920,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
if(headersForm.getSigningWallet() != null) {
|
if(headersForm.getSigningWallet() != null) {
|
||||||
updateSignedKeystores(headersForm.getSigningWallet());
|
updateSignedKeystores(headersForm.getSigningWallet());
|
||||||
} else if(headersForm.getPsbt().isSigned()) {
|
} else if(headersForm.getPsbt().isSigned()) {
|
||||||
Wallet signedWallet = new FinalizingPSBTWallet(headersForm.getPsbt());
|
Wallet signedWallet = new FinalizingPSBTWallet(getTransactionForm().getSigningWallet().getNetwork(), headersForm.getPsbt());
|
||||||
headersForm.setSigningWallet(signedWallet);
|
headersForm.setSigningWallet(signedWallet);
|
||||||
finalizePSBT();
|
finalizePSBT();
|
||||||
EventManager.get().post(new FinalizeTransactionEvent(headersForm.getPsbt(), signedWallet));
|
EventManager.get().post(new FinalizeTransactionEvent(headersForm.getPsbt(), signedWallet));
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ public class InputController extends TransactionFormController implements Initia
|
||||||
if (output != null) {
|
if (output != null) {
|
||||||
spends.setValue(output.getValue());
|
spends.setValue(output.getValue());
|
||||||
try {
|
try {
|
||||||
Address[] addresses = output.getScript().getToAddresses();
|
Address[] addresses = output.getScript().getToAddresses(getTransactionForm().getSigningWallet().getNetwork());
|
||||||
from.setVisible(true);
|
from.setVisible(true);
|
||||||
if (addresses.length == 1) {
|
if (addresses.length == 1) {
|
||||||
address.setAddress(addresses[0]);
|
address.setAddress(addresses[0]);
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ public class OutputController extends TransactionFormController implements Initi
|
||||||
value.setValue(txOutput.getValue());
|
value.setValue(txOutput.getValue());
|
||||||
to.setVisible(false);
|
to.setVisible(false);
|
||||||
try {
|
try {
|
||||||
Address[] addresses = txOutput.getScript().getToAddresses();
|
Address[] addresses = txOutput.getScript().getToAddresses(getTransactionForm().getSigningWallet().getNetwork());
|
||||||
to.setVisible(true);
|
to.setVisible(true);
|
||||||
if(addresses.length == 1) {
|
if(addresses.length == 1) {
|
||||||
address.setAddress(addresses[0]);
|
address.setAddress(addresses[0]);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ public abstract class TransactionFormController extends BaseController {
|
||||||
TransactionOutput output = outputs.get(i);
|
TransactionOutput output = outputs.get(i);
|
||||||
String name = "#" + i;
|
String name = "#" + i;
|
||||||
try {
|
try {
|
||||||
Address[] addresses = output.getScript().getToAddresses();
|
Address[] addresses = output.getScript().getToAddresses(getTransactionForm().getSigningWallet().getNetwork());
|
||||||
if(addresses.length == 1) {
|
if(addresses.length == 1) {
|
||||||
name = name + " " + addresses[0].getAddress();
|
name = name + " " + addresses[0].getAddress();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address getRecipientAddress() throws InvalidAddressException {
|
private Address getRecipientAddress() throws InvalidAddressException {
|
||||||
return Address.fromString(address.getText());
|
return Address.fromString(getWalletForm().getWallet().getNetwork(), address.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long getRecipientValueSats() {
|
private Long getRecipientValueSats() {
|
||||||
|
|
@ -504,7 +504,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
try {
|
try {
|
||||||
address = getRecipientAddress();
|
address = getRecipientAddress();
|
||||||
} catch(InvalidAddressException e) {
|
} catch(InvalidAddressException e) {
|
||||||
address = new P2PKHAddress(new byte[20]);
|
address = new P2PKHAddress(getWalletForm().getWallet().getNetwork(), new byte[20]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionOutput txOutput = new TransactionOutput(new Transaction(), 1L, address.getOutputScript());
|
TransactionOutput txOutput = new TransactionOutput(new Transaction(), 1L, address.getOutputScript());
|
||||||
|
|
@ -531,7 +531,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scanQrAddress(ActionEvent event) {
|
public void scanQrAddress(ActionEvent event) {
|
||||||
QRScanDialog qrScanDialog = new QRScanDialog();
|
QRScanDialog qrScanDialog = new QRScanDialog(getWalletForm().getWallet().getNetwork());
|
||||||
Optional<QRScanDialog.Result> optionalResult = qrScanDialog.showAndWait();
|
Optional<QRScanDialog.Result> optionalResult = qrScanDialog.showAndWait();
|
||||||
if(optionalResult.isPresent()) {
|
if(optionalResult.isPresent()) {
|
||||||
QRScanDialog.Result result = optionalResult.get();
|
QRScanDialog.Result result = optionalResult.get();
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.sparrowwallet.drongo.SecureString;
|
||||||
import com.sparrowwallet.drongo.crypto.*;
|
import com.sparrowwallet.drongo.crypto.*;
|
||||||
import com.sparrowwallet.drongo.policy.Policy;
|
import com.sparrowwallet.drongo.policy.Policy;
|
||||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Network;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||||
|
|
@ -46,6 +47,9 @@ import java.util.stream.Collectors;
|
||||||
public class SettingsController extends WalletFormController implements Initializable {
|
public class SettingsController extends WalletFormController implements Initializable {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SettingsController.class);
|
private static final Logger log = LoggerFactory.getLogger(SettingsController.class);
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ComboBox<Network> network;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<PolicyType> policyType;
|
private ComboBox<PolicyType> policyType;
|
||||||
|
|
||||||
|
|
@ -92,6 +96,12 @@ public class SettingsController extends WalletFormController implements Initiali
|
||||||
keystoreTabs = new TabPane();
|
keystoreTabs = new TabPane();
|
||||||
keystoreTabsPane.getChildren().add(keystoreTabs);
|
keystoreTabsPane.getChildren().add(keystoreTabs);
|
||||||
|
|
||||||
|
network.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, network) -> {
|
||||||
|
walletForm.getWallet().setNetwork(network);
|
||||||
|
|
||||||
|
EventManager.get().post(new SettingsChangedEvent(walletForm.getWallet(), SettingsChangedEvent.Type.NETWORK));
|
||||||
|
});
|
||||||
|
|
||||||
policyType.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, policyType) -> {
|
policyType.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, policyType) -> {
|
||||||
walletForm.getWallet().setPolicyType(policyType);
|
walletForm.getWallet().setPolicyType(policyType);
|
||||||
|
|
||||||
|
|
@ -190,6 +200,8 @@ public class SettingsController extends WalletFormController implements Initiali
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFieldsFromWallet(Wallet wallet) {
|
private void setFieldsFromWallet(Wallet wallet) {
|
||||||
|
network.getSelectionModel().select(walletForm.getWallet().getNetwork());
|
||||||
|
|
||||||
if(wallet.getPolicyType() == null) {
|
if(wallet.getPolicyType() == null) {
|
||||||
wallet.setPolicyType(PolicyType.SINGLE);
|
wallet.setPolicyType(PolicyType.SINGLE);
|
||||||
wallet.setScriptType(ScriptType.P2WPKH);
|
wallet.setScriptType(ScriptType.P2WPKH);
|
||||||
|
|
@ -260,7 +272,7 @@ public class SettingsController extends WalletFormController implements Initiali
|
||||||
Optional<String> text = dialog.showAndWait();
|
Optional<String> text = dialog.showAndWait();
|
||||||
if(text.isPresent() && !text.get().isEmpty() && !text.get().equals(outputDescriptorString)) {
|
if(text.isPresent() && !text.get().isEmpty() && !text.get().equals(outputDescriptorString)) {
|
||||||
try {
|
try {
|
||||||
OutputDescriptor editedOutputDescriptor = OutputDescriptor.getOutputDescriptor(text.get());
|
OutputDescriptor editedOutputDescriptor = OutputDescriptor.getOutputDescriptor(walletForm.getWallet().getNetwork(), text.get());
|
||||||
Wallet editedWallet = editedOutputDescriptor.toWallet();
|
Wallet editedWallet = editedOutputDescriptor.toWallet();
|
||||||
|
|
||||||
editedWallet.setName(getWalletForm().getWallet().getName());
|
editedWallet.setName(getWalletForm().getWallet().getName());
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
<?import org.controlsfx.control.RangeSlider?>
|
<?import org.controlsfx.control.RangeSlider?>
|
||||||
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
|
<?import com.sparrowwallet.sparrow.control.CopyableLabel?>
|
||||||
<?import com.sparrowwallet.drongo.policy.PolicyType?>
|
<?import com.sparrowwallet.drongo.policy.PolicyType?>
|
||||||
|
<?import com.sparrowwallet.drongo.protocol.Network?>
|
||||||
<?import com.sparrowwallet.drongo.protocol.ScriptType?>
|
<?import com.sparrowwallet.drongo.protocol.ScriptType?>
|
||||||
<?import com.sparrowwallet.sparrow.control.DescriptorArea?>
|
<?import com.sparrowwallet.sparrow.control.DescriptorArea?>
|
||||||
<?import org.fxmisc.flowless.VirtualizedScrollPane?>
|
<?import org.fxmisc.flowless.VirtualizedScrollPane?>
|
||||||
|
|
@ -29,6 +30,16 @@
|
||||||
|
|
||||||
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
|
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
|
||||||
<Fieldset inputGrow="SOMETIMES" text="Settings">
|
<Fieldset inputGrow="SOMETIMES" text="Settings">
|
||||||
|
<Field text="Network:">
|
||||||
|
<ComboBox fx:id="network">
|
||||||
|
<items>
|
||||||
|
<FXCollections fx:factory="observableArrayList">
|
||||||
|
<Network fx:constant="BITCOIN" />
|
||||||
|
<Network fx:constant="TESTNET" />
|
||||||
|
</FXCollections>
|
||||||
|
</items>
|
||||||
|
</ComboBox>
|
||||||
|
</Field>
|
||||||
<Field text="Policy Type:">
|
<Field text="Policy Type:">
|
||||||
<ComboBox fx:id="policyType">
|
<ComboBox fx:id="policyType">
|
||||||
<items>
|
<items>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue