WIP - testnet support

This commit is contained in:
Daniel Newton 2020-09-27 22:05:46 +13:00
parent 2cb667a671
commit 4c94e52ef7
19 changed files with 98 additions and 42 deletions

2
drongo

@ -1 +1 @@
Subproject commit e8d8fa61268ec8ac4dd5c14e6715d4a4bde2fe49 Subproject commit 6d156505587bbbcddb5bea001cf21fbe6195e863

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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")) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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