initial policy type related changes from drongo

This commit is contained in:
Craig Raw
2026-04-21 11:34:14 +02:00
parent 110f887952
commit 8780e515d5
31 changed files with 96 additions and 88 deletions
+1 -1
Submodule drongo updated: dad9fe2fcc...15e5aaa4b9
@@ -1121,7 +1121,7 @@ public class AppController implements Initializable {
WalletNameDialog.NameAndBirthDate nameAndBirthDate = optNameAndBirthDate.get();
File walletFile = Storage.getWalletFile(nameAndBirthDate.getName());
Storage storage = new Storage(walletFile);
Wallet wallet = new Wallet(nameAndBirthDate.getName(), PolicyType.SINGLE, ScriptType.P2WPKH, nameAndBirthDate.getBirthDate());
Wallet wallet = new Wallet(nameAndBirthDate.getName(), PolicyType.SINGLE_HD, ScriptType.P2WPKH, nameAndBirthDate.getBirthDate());
addWalletTabOrWindow(storage, wallet, false);
}
}
@@ -1271,7 +1271,7 @@ public class AppController implements Initializable {
List<ExtendedKey> xpubs = wallet.getKeystores().stream().map(Keystore::getExtendedPublicKey).collect(Collectors.toList());
Optional<WalletForm> optNewWalletForm = walletTabData.stream()
.map(WalletTabData::getWalletForm)
.filter(wf -> wf.getSettingsWalletForm() != null && wf.getSettingsWalletForm().getWallet().getPolicyType() == PolicyType.MULTI &&
.filter(wf -> wf.getSettingsWalletForm() != null && wf.getSettingsWalletForm().getWallet().getPolicyType() == PolicyType.MULTI_HD &&
wf.getSettingsWalletForm().getWallet().getScriptType() == wallet.getScriptType() && !wf.getSettingsWalletForm().getWallet().isValid() &&
wf.getSettingsWalletForm().getWallet().getKeystores().stream().map(Keystore::getExtendedPublicKey).anyMatch(xpubs::contains)).findFirst();
if(optNewWalletForm.isPresent()) {
@@ -1077,7 +1077,7 @@ public class AppServices {
try {
Auth47 auth47 = new Auth47(uri);
List<ScriptType> scriptTypes = PaymentCode.SEGWIT_SCRIPT_TYPES;
Wallet wallet = selectWallet(List.of(PolicyType.SINGLE), scriptTypes, false, true, "login to " + auth47.getCallback().getHost(), true);
Wallet wallet = selectWallet(List.of(PolicyType.SINGLE_HD), scriptTypes, false, true, "login to " + auth47.getCallback().getHost(), true);
if(wallet != null) {
try {
@@ -1097,8 +1097,8 @@ public class AppServices {
private static void openLnurlAuthUri(URI uri) {
try {
LnurlAuth lnurlAuth = new LnurlAuth(uri);
List<ScriptType> scriptTypes = ScriptType.getAddressableScriptTypes(PolicyType.SINGLE);
Wallet wallet = selectWallet(List.of(PolicyType.SINGLE), scriptTypes, true, true, lnurlAuth.getLoginMessage(), true);
List<ScriptType> scriptTypes = ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD);
Wallet wallet = selectWallet(List.of(PolicyType.SINGLE_HD), scriptTypes, true, true, lnurlAuth.getLoginMessage(), true);
if(wallet != null) {
if(wallet.isEncrypted()) {
@@ -55,7 +55,8 @@ public abstract class BaseController {
descriptorArea.setMouseOverTextDelay(Duration.ofMillis(150));
descriptorArea.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_BEGIN, e -> {
TwoDimensional.Position position = descriptorArea.getParagraph(0).getStyleSpans().offsetToPosition(e.getCharacterIndex(), Backward);
int index = descriptorArea.getWallet().getPolicyType() == PolicyType.SINGLE ? position.getMajor() - 1 : ((position.getMajor() - 1) / 2);
int index = descriptorArea.getWallet().getPolicyType() == PolicyType.SINGLE || descriptorArea.getWallet().getPolicyType() == PolicyType.SINGLE_SILENT_PAYMENTS ?
position.getMajor() - 1 : ((position.getMajor() - 1) / 2);
if(position.getMajor() > 0 && index >= 0 && index < descriptorArea.getWallet().getKeystores().size()) {
Keystore hoverKeystore = descriptorArea.getWallet().getKeystores().get(index);
Point2D pos = e.getScreenPosition();
@@ -775,10 +775,10 @@ public class DevicePane extends TitledDescriptionPane {
if(wallet.getScriptType() == null) {
ScriptType scriptType = Arrays.stream(ScriptType.ADDRESSABLE_TYPES).filter(type -> type.getDefaultDerivation().get(0).equals(derivation.get(0))).findFirst().orElse(ScriptType.P2PKH);
wallet.setName(device.getModel().toDisplayString());
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, scriptType, wallet.getKeystores(), null));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, scriptType, wallet.getKeystores(), null));
EventManager.get().post(new WalletImportEvent(wallet));
} else {
@@ -926,7 +926,7 @@ public class DevicePane extends TitledDescriptionPane {
List<StandardAccount> discoveryAccounts = new ArrayList<>(Arrays.asList(StandardAccount.values()).subList(0, optRange.get() + 1));
Map<Hwi.WalletType, String> derivationPaths = new LinkedHashMap<>();
List<ScriptType> scriptTypes = new ArrayList<>(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE));
List<ScriptType> scriptTypes = new ArrayList<>(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD));
if(device.getModel() == WalletModel.BITBOX_02) {
scriptTypes.remove(ScriptType.P2PKH);
}
@@ -943,7 +943,7 @@ public class DevicePane extends TitledDescriptionPane {
for(Map.Entry<Hwi.WalletType, String> entry : accountXpubs.entrySet()) {
try {
Wallet wallet = new Wallet(device.getModel().toDisplayString());
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(entry.getKey().scriptType());
Keystore keystore = new Keystore();
keystore.setLabel(device.getModel().toDisplayString());
@@ -952,7 +952,7 @@ public class DevicePane extends TitledDescriptionPane {
keystore.setKeyDerivation(new KeyDerivation(device.getFingerprint(), derivationPaths.get(entry.getKey())));
keystore.setExtendedPublicKey(ExtendedKey.fromDescriptor(entry.getValue()));
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, entry.getKey().scriptType(), wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, entry.getKey().scriptType(), wallet.getKeystores(), 1));
if(entry.getKey().standardAccount().equals(StandardAccount.ACCOUNT_0)) {
wallets.add(wallet);
} else {
@@ -50,12 +50,12 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
this.fileName = fileName;
this.password = password;
List<ScriptType> scriptTypes = ScriptType.getAddressableScriptTypes(PolicyType.SINGLE);
List<ScriptType> scriptTypes = ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD);
if(wallets != null && !wallets.isEmpty()) {
if(wallets.size() == 1 && scriptTypes.contains(wallets.get(0).getScriptType())) {
Wallet wallet = wallets.get(0);
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, wallet.getScriptType(), wallet.getKeystores(), null));
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, wallet.getScriptType(), wallet.getKeystores(), null));
wallet.setName(importer.getName());
EventManager.get().post(new WalletImportEvent(wallets.get(0)));
} else {
@@ -81,8 +81,8 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
if(wallets != null && !wallets.isEmpty()) {
Wallet wallet = wallets.stream().filter(wallet1 -> wallet1.getScriptType() == scriptType).findFirst().orElseThrow(ImportException::new);
wallet.setName(importer.getName());
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, wallet.getScriptType(), wallet.getKeystores(), null));
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, wallet.getScriptType(), wallet.getKeystores(), null));
EventManager.get().post(new WalletImportEvent(wallet));
} else {
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
@@ -90,10 +90,10 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
Wallet wallet = new Wallet();
wallet.setName(Files.getNameWithoutExtension(fileName));
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, scriptType, wallet.getKeystores(), null));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, scriptType, wallet.getKeystores(), null));
EventManager.get().post(new WalletImportEvent(wallet));
}
@@ -25,8 +25,6 @@ import com.sparrowwallet.sparrow.io.Storage;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
@@ -297,8 +295,8 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
}
private void checkWalletSigning(Wallet wallet) {
if(wallet.getKeystores().size() != 1) {
throw new IllegalArgumentException("Cannot sign messages using a wallet with multiple keystores - a single key is required");
if(wallet.getKeystores().size() != 1 || wallet.getPolicyType() != PolicyType.SINGLE_HD) {
throw new IllegalArgumentException("Cannot sign messages using a non-HD wallet or a wallet with multiple keystores");
}
}
@@ -323,7 +321,7 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
private boolean isValidAddress() {
try {
Address address = getAddress();
return address.getScriptType().isAllowed(PolicyType.SINGLE) || address.getScriptType() == ScriptType.P2SH;
return address.getScriptType().isAllowed(PolicyType.SINGLE_HD) || address.getScriptType() == ScriptType.P2SH;
} catch (InvalidAddressException e) {
return false;
}
@@ -466,11 +464,11 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
if(scriptType == ScriptType.P2SH) {
scriptType = ScriptType.P2SH_P2WPKH;
}
if(!ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE).contains(scriptType)) {
if(!ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE_HD).contains(scriptType)) {
throw new IllegalArgumentException("Only single signature P2PKH, P2SH-P2WPKH or P2WPKH addresses can verify messages.");
}
Address signedMessageAddress = scriptType.getAddress(signedMessageKey);
Address signedMessageAddress = scriptType.getAddress(PolicyType.SINGLE_HD, signedMessageKey);
return providedAddress.equals(signedMessageAddress);
}
@@ -527,7 +525,7 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
psbtInput.setTapInternalKey(pubKey);
psbtInput.getTapDerivedPublicKeys().put(ECKey.fromPublicOnly(pubKey.getPubKeyXCoord()), Map.of(fullDerivation, Collections.emptyList()));
} else {
psbtInput.getDerivedPublicKeys().put(scriptType.getOutputKey(pubKey), fullDerivation);
psbtInput.getDerivedPublicKeys().put(scriptType.getOutputKey(signingWallet.getPolicyType(), pubKey), fullDerivation);
}
}
@@ -108,11 +108,11 @@ public class MnemonicWalletKeystoreImportPane extends MnemonicKeystorePane {
discoverButton.setGraphic(progressIndicator);
List<Wallet> wallets = new ArrayList<>();
List<List<ChildNumber>> derivations = ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE).stream().map(ScriptType::getDefaultDerivation).collect(Collectors.toList());
List<List<ChildNumber>> derivations = ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE_HD).stream().map(ScriptType::getDefaultDerivation).collect(Collectors.toList());
derivations.add(List.of(new ChildNumber(0, true)));
derivations.add(ScriptType.P2PKH.getDefaultDerivation(1)); //Bisq segwit misderivation
for(ScriptType scriptType : ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE)) {
for(ScriptType scriptType : ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE_HD)) {
for(List<ChildNumber> derivation : derivations) {
try {
Wallet wallet = getWallet(scriptType, derivation);
@@ -165,11 +165,11 @@ public class MnemonicWalletKeystoreImportPane extends MnemonicKeystorePane {
private Wallet getWallet(ScriptType scriptType, List<ChildNumber> derivation) throws ImportException {
Wallet wallet = new Wallet("");
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType);
Keystore keystore = importer.getKeystore(derivation, wordEntriesProperty.get(), passphraseProperty.get());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, scriptType, wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, scriptType, wallet.getKeystores(), 1));
return wallet;
}
@@ -178,7 +178,7 @@ public class MnemonicWalletKeystoreImportPane extends MnemonicKeystorePane {
HBox fieldBox = new HBox(5);
fieldBox.setAlignment(Pos.CENTER_RIGHT);
ComboBox<ScriptType> scriptTypeComboBox = new ComboBox<>(FXCollections.observableArrayList(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE)));
ComboBox<ScriptType> scriptTypeComboBox = new ComboBox<>(FXCollections.observableArrayList(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD)));
if(scriptTypeComboBox.getItems().contains(ScriptType.P2WPKH)) {
scriptTypeComboBox.setValue(ScriptType.P2WPKH);
}
@@ -109,7 +109,7 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
Field keyScriptTypeField = new Field();
keyScriptTypeField.setText("Script Type:");
keyScriptType = new ComboBox<>();
keyScriptType.setItems(FXCollections.observableList(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE)));
keyScriptType.setItems(FXCollections.observableList(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD)));
keyScriptTypeField.getInputs().add(keyScriptType);
keyScriptType.setConverter(new StringConverter<ScriptType>() {
@@ -287,14 +287,14 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
private void setFromAddress() {
DumpedPrivateKey privateKey = getPrivateKey();
ScriptType scriptType = keyScriptType.getValue();
Address address = scriptType.getAddress(privateKey.getKey());
Address address = scriptType.getAddress(PolicyType.SINGLE_HD, privateKey.getKey());
keyAddress.setText(address.toString());
}
private void setScriptTypes(boolean isValidKey) {
boolean compressed = !isValidKey || getPrivateKey().getKey().isCompressed();
if(compressed && !keyScriptType.getItems().equals(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE))) {
keyScriptType.getItems().addAll(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE).stream().filter(s -> !keyScriptType.getItems().contains(s)).collect(Collectors.toList()));
if(compressed && !keyScriptType.getItems().equals(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD))) {
keyScriptType.getItems().addAll(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD).stream().filter(s -> !keyScriptType.getItems().contains(s)).collect(Collectors.toList()));
} else if(!compressed && !keyScriptType.getItems().equals(List.of(ScriptType.P2PKH))) {
keyScriptType.getSelectionModel().select(0);
keyScriptType.getItems().removeIf(scriptType -> scriptType != ScriptType.P2PKH);
@@ -346,7 +346,7 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
try {
DumpedPrivateKey privateKey = getPrivateKey();
ScriptType scriptType = keyScriptType.getValue();
Address fromAddress = scriptType.getAddress(privateKey.getKey());
Address fromAddress = scriptType.getAddress(PolicyType.SINGLE_HD, privateKey.getKey());
Address destAddress = getToAddress();
Date since = null;
@@ -389,7 +389,7 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
Transaction noFeeTransaction = new Transaction();
long total = 0;
for(TransactionOutput txOutput : txOutputs) {
scriptType.addSpendingInput(noFeeTransaction, txOutput, pubKey, TransactionSignature.dummy(scriptType == P2TR ? TransactionSignature.Type.SCHNORR : TransactionSignature.Type.ECDSA));
scriptType.addSpendingInput(PolicyType.SINGLE_HD, noFeeTransaction, txOutput, pubKey, TransactionSignature.dummy(scriptType == P2TR ? TransactionSignature.Type.SCHNORR : TransactionSignature.Type.ECDSA));
total += txOutput.getValue();
}
@@ -448,7 +448,7 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
psbtInput.setWitnessScript(txInput.getWitness().getWitnessScript());
}
if(!psbtInput.sign(scriptType.getOutputKey(privKey))) {
if(!psbtInput.sign(scriptType.getOutputKey(PolicyType.SINGLE_HD, privKey))) {
AppServices.showErrorDialog("Failed to sign", "Failed to sign for transaction output " + utxoOutput.getHash() + ":" + utxoOutput.getIndex());
return;
}
@@ -456,7 +456,7 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
TransactionSignature signature = psbtInput.isTaproot() ? psbtInput.getTapKeyPathSignature() : psbtInput.getPartialSignature(pubKey);
Transaction finalizeTransaction = new Transaction();
TransactionInput finalizedTxInput = scriptType.addSpendingInput(finalizeTransaction, utxoOutput, pubKey, signature);
TransactionInput finalizedTxInput = scriptType.addSpendingInput(PolicyType.SINGLE_HD, finalizeTransaction, utxoOutput, pubKey, signature);
psbtInput.setFinalScriptSig(finalizedTxInput.getScriptSig());
psbtInput.setFinalScriptWitness(finalizedTxInput.getWitness());
}
@@ -49,6 +49,8 @@ public class WalletExportDialog extends Dialog<Wallet> {
} else if(wallet.getPolicyType() == PolicyType.MULTI) {
exporters = List.of(new Bip129(), new CaravanMultisig(), new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new ElectrumPersonalServer(), new KeystoneMultisig(),
new Descriptor(), new JadeMultisig(), new PassportMultisig(), new SpecterDesktop(), new BlueWalletMultisig(), new SpecterDIY(), new Sparrow(), new WalletLabels(allWalletForms), new WalletTransactions(selectedWalletForm));
} else if(wallet.getPolicyType() == PolicyType.SINGLE_SILENT_PAYMENTS) {
exporters = List.of(new Sparrow(), new WalletLabels(allWalletForms), new WalletTransactions(selectedWalletForm));
} else {
throw new UnsupportedOperationException("Cannot export wallet with policy type " + wallet.getPolicyType());
}
@@ -49,7 +49,7 @@ public class CaravanMultisig implements WalletImport, WalletExport {
Wallet wallet = new Wallet();
wallet.setName(cf.name);
wallet.setPolicyType(PolicyType.MULTI);
wallet.setPolicyType(PolicyType.MULTI_HD);
ScriptType scriptType = ScriptType.valueOf(cf.addressType.replace('-', '_'));
for(ExtPublicKey extKey : cf.extendedPublicKeys) {
@@ -80,7 +80,7 @@ public class CaravanMultisig implements WalletImport, WalletExport {
}
wallet.setScriptType(scriptType);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, scriptType, wallet.getKeystores(), cf.quorum.requiredSigners));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI_HD, scriptType, wallet.getKeystores(), cf.quorum.requiredSigners));
return wallet;
} catch(Exception e) {
@@ -99,7 +99,7 @@ public class CaravanMultisig implements WalletImport, WalletExport {
throw new ExportException("Cannot export an incomplete wallet");
}
if(!wallet.getPolicyType().equals(PolicyType.MULTI)) {
if(!wallet.getPolicyType().equals(PolicyType.MULTI_HD)) {
throw new ExportException(getName() + " import requires a multisig wallet");
}
@@ -73,10 +73,10 @@ public class CoboVaultSinglesig implements KeystoreFileImport, WalletImport {
Keystore keystore = getKeystore(ScriptType.P2WPKH, inputStream, "");
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2WPKH);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, wallet.getKeystores(), null));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, wallet.getKeystores(), null));
try {
wallet.checkWallet();
@@ -119,7 +119,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
@Override
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.MULTI);
wallet.setPolicyType(PolicyType.MULTI_HD);
int threshold = 2;
ScriptType scriptType = ScriptType.P2SH;
@@ -167,7 +167,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
}
Policy policy = Policy.getPolicy(PolicyType.MULTI, scriptType, wallet.getKeystores(), threshold);
Policy policy = Policy.getPolicy(PolicyType.MULTI_HD, scriptType, wallet.getKeystores(), threshold);
wallet.setDefaultPolicy(policy);
wallet.setScriptType(scriptType);
@@ -194,7 +194,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
throw new ExportException("Cannot export an incomplete wallet");
}
if(!wallet.getPolicyType().equals(PolicyType.MULTI)) {
if(!wallet.getPolicyType().equals(PolicyType.MULTI_HD)) {
throw new ExportException(getName() + " import requires a multisig wallet");
}
@@ -104,10 +104,10 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
Keystore keystore = getKeystore(ScriptType.P2WPKH, inputStream, "");
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2WPKH);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, wallet.getKeystores(), null));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, wallet.getKeystores(), null));
try {
wallet.checkWallet();
@@ -43,7 +43,7 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
Wallet wallet = importWallet(inputStream, password);
if(!wallet.getPolicyType().equals(PolicyType.SINGLE) || wallet.getKeystores().size() != 1) {
if(!wallet.getPolicyType().equals(PolicyType.SINGLE_HD) || wallet.getKeystores().size() != 1) {
throw new ImportException("Multisig wallet detected - import it using File > Import Wallet");
}
@@ -203,13 +203,13 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
wallet.setScriptType(scriptType);
if(ew.wallet_type.equals("standard")) {
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, scriptType, wallet.getKeystores(), 1));
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, scriptType, wallet.getKeystores(), 1));
} else if(ew.wallet_type.contains("of")) {
wallet.setPolicyType(PolicyType.MULTI);
wallet.setPolicyType(PolicyType.MULTI_HD);
String[] mOfn = ew.wallet_type.split("of");
int threshold = Integer.parseInt(mOfn[0]);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, scriptType, wallet.getKeystores(), threshold));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI_HD, scriptType, wallet.getKeystores(), threshold));
} else {
throw new ImportException("Unknown Electrum wallet type of " + ew.wallet_type);
}
@@ -308,9 +308,9 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
public void exportWallet(Wallet wallet, OutputStream outputStream, String password) throws ExportException {
try {
ElectrumJsonWallet ew = new ElectrumJsonWallet();
if(wallet.getPolicyType().equals(PolicyType.SINGLE)) {
if(wallet.getPolicyType().equals(PolicyType.SINGLE_HD)) {
ew.wallet_type = "standard";
} else if(wallet.getPolicyType().equals(PolicyType.MULTI)) {
} else if(wallet.getPolicyType().equals(PolicyType.MULTI_HD)) {
ew.wallet_type = wallet.getDefaultPolicy().getNumSignaturesRequired() + "of" + wallet.getKeystores().size();
} else {
throw new ExportException("Could not export a wallet with a " + wallet.getPolicyType() + " policy");
@@ -367,9 +367,9 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
throw new ExportException("Cannot export a keystore of source " + keystore.getSource());
}
if(wallet.getPolicyType().equals(PolicyType.SINGLE)) {
if(wallet.getPolicyType().equals(PolicyType.SINGLE_HD)) {
ew.keystores.put("keystore", ek);
} else if(wallet.getPolicyType().equals(PolicyType.MULTI)) {
} else if(wallet.getPolicyType().equals(PolicyType.MULTI_HD)) {
ew.keystores.put("x" + index + "/", ek);
}
@@ -30,6 +30,10 @@ public class ElectrumPersonalServer implements WalletExport {
@Override
public void exportWallet(Wallet wallet, OutputStream outputStream, String password) throws ExportException {
if(wallet.getPolicyType() == PolicyType.SINGLE_SILENT_PAYMENTS) {
throw new ExportException(getName() + " does not support silent payments wallets.");
}
if(wallet.getScriptType() == ScriptType.P2TR) {
throw new ExportException(getName() + " does not support Taproot wallets.");
}
@@ -1,6 +1,5 @@
package com.sparrowwallet.sparrow.io;
import com.google.gson.Gson;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.OutputDescriptor;
@@ -79,10 +78,10 @@ public class KeystoneSinglesig implements KeystoreFileImport, WalletImport {
Keystore keystore = getKeystore(ScriptType.P2WPKH, inputStream, "");
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2WPKH);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, wallet.getKeystores(), null));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, wallet.getKeystores(), null));
try {
wallet.checkWallet();
@@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.*;
import com.sparrowwallet.drongo.crypto.*;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.MnemonicException;
import com.sparrowwallet.drongo.wallet.StandardAccount;
@@ -187,6 +188,7 @@ public class Storage {
keystore.setExtendedPublicKey(derivedKeystore.getExtendedPublicKey());
keystore.getSeed().setPassphrase(copyKeystore.getSeed().getPassphrase());
keystore.setBip47ExtendedPrivateKey(derivedKeystore.getBip47ExtendedPrivateKey());
keystore.setSilentPaymentScanAddress(wallet.getPolicyType() == PolicyType.SINGLE_SILENT_PAYMENTS ? derivedKeystore.getSilentPaymentScanAddress() : null);
copyKeystore.getSeed().clear();
} else if(keystore.hasMasterPrivateExtendedKey()) {
Keystore copyKeystore = copy.getKeystores().get(i);
@@ -194,6 +196,7 @@ public class Storage {
keystore.setKeyDerivation(derivedKeystore.getKeyDerivation());
keystore.setExtendedPublicKey(derivedKeystore.getExtendedPublicKey());
keystore.setBip47ExtendedPrivateKey(derivedKeystore.getBip47ExtendedPrivateKey());
keystore.setSilentPaymentScanAddress(wallet.getPolicyType() == PolicyType.SINGLE_SILENT_PAYMENTS ? derivedKeystore.getSilentPaymentScanAddress() : null);
copyKeystore.getMasterPrivateKey().clear();
}
}
@@ -6,6 +6,7 @@ import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.crypto.ChildNumber;
import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
@@ -300,7 +301,7 @@ public class CkCardApi extends CardApi {
}
CardRead cardRead = cardProtocol.read(null, currentSlot);
Address address = getDefaultScriptType().getAddress(cardRead.getPubKey());
Address address = getDefaultScriptType().getAddress(PolicyType.SINGLE_HD, cardRead.getPubKey());
String left = addr.substring(0, addr.indexOf('_'));
String right = addr.substring(addr.lastIndexOf('_') + 1);
@@ -151,8 +151,8 @@ public class LnurlAuth {
}
private ECKey deriveLinkingKey(Wallet wallet) {
if(wallet.getPolicyType() != PolicyType.SINGLE) {
throw new IllegalArgumentException("Only singlesig wallets can authenticate.");
if(wallet.getPolicyType() != PolicyType.SINGLE_HD) {
throw new IllegalArgumentException("Only singlesig HD wallets can authenticate.");
}
if(wallet.isEncrypted()) {
@@ -4,6 +4,7 @@ import com.sparrowwallet.drongo.Version;
import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.address.InvalidAddressException;
import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.SparrowWallet;
@@ -66,7 +67,7 @@ public class VersionCheckService extends ScheduledService<VersionUpdatedEvent> {
String signature = versionCheck.signatures.get(addressString);
ECKey signedMessageKey = ECKey.signedMessageToKey(versionCheck.version, signature, false);
Address providedAddress = Address.fromString(addressString);
Address signedMessageAddress = ScriptType.P2PKH.getAddress(signedMessageKey);
Address signedMessageAddress = ScriptType.P2PKH.getAddress(PolicyType.SINGLE_HD, signedMessageKey);
if(providedAddress.equals(signedMessageAddress)) {
return true;
@@ -68,7 +68,7 @@ public class Bip39Dialog extends NewWalletDialog {
buttonPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER,false,false)).addTo(mainPanel);
setComponent(mainPanel);
ScriptType.getAddressableScriptTypes(PolicyType.SINGLE).stream().map(DisplayScriptType::new).forEach(scriptType::addItem);
ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD).stream().map(DisplayScriptType::new).forEach(scriptType::addItem);
scriptType.setSelectedItem(new DisplayScriptType(ScriptType.P2WPKH));
seedWords.setTextChangeListener((newText, changedByUserInteraction) -> {
@@ -150,11 +150,11 @@ public class Bip39Dialog extends NewWalletDialog {
@Override
protected List<Wallet> getWallets() throws ImportException {
Wallet wallet = new Wallet(walletName);
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType.getSelectedItem().scriptType);
Keystore keystore = importer.getKeystore(wallet.getScriptType().getDefaultDerivation(), getWords(), passphrase.getText());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, wallet.getScriptType(), wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, wallet.getScriptType(), wallet.getKeystores(), 1));
return List.of(wallet);
}
@@ -75,7 +75,7 @@ public class SettingsDialog extends WalletDialog {
Panel leftButtonPanel = new Panel();
leftButtonPanel.setLayoutManager(new GridLayout(2).setHorizontalSpacing(1));
leftButtonPanel.addComponent(new Button("Add Account", this::showAddAccount));
if(getWalletForm().getWallet().getPolicyType() == PolicyType.SINGLE) {
if(getWalletForm().getWallet().getPolicyType() == PolicyType.SINGLE || getWalletForm().getWallet().getPolicyType() == PolicyType.SINGLE_SILENT_PAYMENTS) {
leftButtonPanel.addComponent(new Button("Show Seed", this::showSeed));
} else {
leftButtonPanel.addComponent(new EmptySpace(TerminalSize.ZERO));
@@ -113,12 +113,12 @@ public class WatchOnlyDialog extends NewWalletDialog {
Set<ScriptType> scriptTypes = new LinkedHashSet<>();
scriptTypes.add(ScriptType.P2WPKH);
scriptTypes.add(header.getDefaultScriptType());
scriptTypes.addAll(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE));
scriptTypes.addAll(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE_HD));
List<Wallet> wallets = new ArrayList<>();
for(ScriptType scriptType : scriptTypes) {
Wallet wallet = new Wallet(walletName);
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType);
Keystore keystore = new Keystore();
@@ -849,7 +849,7 @@ public class HeadersController extends TransactionFormController implements Init
}
if(headersForm.getWalletTransaction() != null && headersForm.getWalletTransaction().getWallet() != null
&& headersForm.getWalletTransaction().getWallet().getPolicyType() == PolicyType.MULTI
&& headersForm.getWalletTransaction().getWallet().getPolicyType() == PolicyType.MULTI_HD
&& headersForm.getWalletTransaction().getWallet().getDefaultPolicy().getNumSignaturesRequired() < headersForm.getWalletTransaction().getWallet().getKeystores().size()) {
signedByField.setVisible(true);
Wallet wallet = headersForm.getWalletTransaction().getWallet();
@@ -61,7 +61,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.TimeoutException;
@@ -571,7 +570,7 @@ public class PaymentController extends WalletFormController implements Initializ
sendNode = recipientBip47Wallet.getFreshNode(KeyPurpose.SEND, sendNode);
}
ECKey pubKey = sendNode.getPubKey();
return recipientBip47Wallet.getScriptType().getAddress(pubKey);
return recipientBip47Wallet.getScriptType().getAddress(recipientBip47Wallet.getPolicyType(), pubKey);
}
} catch(InvalidPaymentCodeException e) {
log.error("Error creating payment code from PayNym", e);
@@ -19,7 +19,7 @@ public class CaravanMultisigTest extends IoTest {
CaravanMultisig ccMultisig = new CaravanMultisig();
Wallet wallet = ccMultisig.importWallet(getInputStream("caravan-multisig-export-1.json"), null);
Assertions.assertEquals("Test Wallet", wallet.getName());
Assertions.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.MULTI_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2WSH, wallet.getScriptType());
Assertions.assertEquals(2, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("wsh(sortedmulti(2,mercury,venus,earth))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -62,7 +62,7 @@ public class ColdcardMultisigTest extends IoTest {
ColdcardMultisig ccMultisig = new ColdcardMultisig();
Wallet wallet = ccMultisig.importWallet(getInputStream("cc-multisig-export-1.txt"), null);
Assertions.assertEquals("CC-2-of-4", wallet.getName());
Assertions.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.MULTI_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2WSH, wallet.getScriptType());
Assertions.assertEquals(2, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("wsh(sortedmulti(2,coldcard1,coldcard2,coldcard3,coldcard4))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -75,7 +75,7 @@ public class ColdcardMultisigTest extends IoTest {
ColdcardMultisig ccMultisig = new ColdcardMultisig();
Wallet wallet = ccMultisig.importWallet(getInputStream("cc-multisig-export-2.txt"), null);
Assertions.assertEquals("CC-2-of-4", wallet.getName());
Assertions.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.MULTI_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2SH_P2WSH, wallet.getScriptType());
Assertions.assertEquals(2, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("sh(wsh(sortedmulti(2,coldcard1,coldcard2,coldcard3,coldcard4)))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -87,7 +87,7 @@ public class ColdcardMultisigTest extends IoTest {
ColdcardMultisig ccMultisig = new ColdcardMultisig();
Wallet wallet = ccMultisig.importWallet(getInputStream("cc-multisig-export-multideriv.txt"), null);
Assertions.assertEquals("el-CC-3-of-3-sb-2", wallet.getName());
Assertions.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.MULTI_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2WSH, wallet.getScriptType());
Assertions.assertEquals(3, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("wsh(sortedmulti(3,coldcard1,coldcard2,coldcard3))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -22,7 +22,7 @@ public class ElectrumTest extends IoTest {
Electrum electrum = new Electrum();
Wallet wallet = electrum.importWallet(getInputStream("electrum-singlesig-wallet.json"), null);
Assertions.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.SINGLE_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2SH_P2WPKH, wallet.getScriptType());
Assertions.assertEquals(1, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("sh(wpkh(trezortest))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -42,7 +42,7 @@ public class ElectrumTest extends IoTest {
wallet = electrum.importWallet(new ByteArrayInputStream(baos.toByteArray()), null);
Assertions.assertTrue(wallet.isValid());
Assertions.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.SINGLE_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2SH_P2WPKH, wallet.getScriptType());
Assertions.assertEquals(1, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("sh(wpkh(trezortest))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -57,7 +57,7 @@ public class ElectrumTest extends IoTest {
Electrum electrum = new Electrum();
Wallet wallet = electrum.importWallet(getInputStream("electrum-multisig-wallet.json"), null);
Assertions.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.MULTI_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2SH_P2WSH, wallet.getScriptType());
Assertions.assertEquals(2, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("sh(wsh(sortedmulti(2,coldcard6ba6cfd,coldcard747b698,coldcard7bb026b,coldcard0f05694)))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -80,7 +80,7 @@ public class ElectrumTest extends IoTest {
wallet = electrum.importWallet(new ByteArrayInputStream(baos.toByteArray()), null);
Assertions.assertTrue(wallet.isValid());
Assertions.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.MULTI_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2SH_P2WSH, wallet.getScriptType());
Assertions.assertEquals(2, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("sh(wsh(sortedmulti(2,coldcard6ba6cfd,coldcard747b698,coldcard7bb026b,coldcard0f05694)))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -98,7 +98,7 @@ public class ElectrumTest extends IoTest {
Wallet wallet = electrum.importWallet(new ByteArrayInputStream(walletBytes), "pass");
Assertions.assertTrue(wallet.isValid());
Assertions.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.SINGLE_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2WPKH, wallet.getScriptType());
Assertions.assertEquals(1, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("wpkh(electrum)", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -118,7 +118,7 @@ public class ElectrumTest extends IoTest {
wallet = electrum.importWallet(new ByteArrayInputStream(baos.toByteArray()), null);
Assertions.assertTrue(wallet.isValid());
Assertions.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.SINGLE_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2WPKH, wallet.getScriptType());
Assertions.assertEquals(1, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("wpkh(electrum)", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -14,7 +14,7 @@ public class SpecterDesktopTest extends IoTest {
SpecterDesktop specterDesktop = new SpecterDesktop();
Wallet wallet = specterDesktop.importWallet(getInputStream("specter-wallet.json"), null);
Assertions.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.SINGLE_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2SH_P2WPKH, wallet.getScriptType());
Assertions.assertEquals(1, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("sh(wpkh(keystore1))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -29,7 +29,7 @@ public class SpecterDesktopTest extends IoTest {
SpecterDesktop specterDesktop = new SpecterDesktop();
Wallet wallet = specterDesktop.importWallet(getInputStream("specter-multisig-wallet.json"), null);
Assertions.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.MULTI_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2WSH, wallet.getScriptType());
Assertions.assertEquals(3, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("wsh(sortedmulti(3,keystore1,keystore2,keystore3,keystore4))", wallet.getDefaultPolicy().getMiniscript().getScript().toLowerCase(Locale.ROOT));
@@ -45,7 +45,7 @@ public class StorageTest extends IoTest {
Assertions.assertTrue(wallet.isValid());
Assertions.assertEquals("testd2", wallet.getName());
Assertions.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
Assertions.assertEquals(PolicyType.SINGLE_HD, wallet.getPolicyType());
Assertions.assertEquals(ScriptType.P2WPKH, wallet.getScriptType());
Assertions.assertEquals(1, wallet.getDefaultPolicy().getNumSignaturesRequired());
Assertions.assertEquals("pkh(60bcd3a7)", wallet.getDefaultPolicy().getMiniscript().getScript());