add initial support for silent payments wallets

This commit is contained in:
Craig Raw 2026-04-14 15:11:47 +02:00
parent 3a1712bdbf
commit 3b8677e59b
17 changed files with 213 additions and 128 deletions

View File

@ -110,6 +110,20 @@ public class KeyDerivation {
return List.of(new ChildNumber(352, true), new ChildNumber(Network.get() == Network.MAINNET ? 0 : 1, true), new ChildNumber(Math.max(0, account), true));
}
public static List<ChildNumber> getBip352ScanDerivation(List<ChildNumber> derivation) {
List<ChildNumber> scanDerivation = new ArrayList<>(derivation);
scanDerivation.add(new ChildNumber(1, true));
scanDerivation.add(new ChildNumber(0, false));
return Collections.unmodifiableList(scanDerivation);
}
public static List<ChildNumber> getBip352SpendDerivation(List<ChildNumber> derivation) {
List<ChildNumber> spendDerivation = new ArrayList<>(derivation);
spendDerivation.add(new ChildNumber(0, true));
spendDerivation.add(new ChildNumber(0, false));
return Collections.unmodifiableList(spendDerivation);
}
public KeyDerivation copy() {
return new KeyDerivation(masterFingerprint, derivationPath);
}

View File

@ -3,16 +3,16 @@ package com.sparrowwallet.drongo;
import java.util.Locale;
public enum Network {
MAINNET("mainnet", "Mainnet", "mainnet", 0, "1", 5, "3", "bc", "sp", ExtendedKey.Header.xprv, ExtendedKey.Header.xpub, 128, 8332),
TESTNET("testnet", "Testnet3", "testnet3", 111, "mn", 196, "2", "tb", "tsp", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18332),
REGTEST("regtest", "Regtest", "regtest", 111, "mn", 196, "2", "bcrt", "sprt", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18443),
SIGNET("signet", "Signet", "signet", 111, "mn", 196, "2", "tb", "tsp", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 38332),
TESTNET4("testnet4", "Testnet4", "testnet4", 111, "mn", 196, "2", "tb", "tsp", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 48332);
MAINNET("mainnet", "Mainnet", "mainnet", 0, "1", 5, "3", "bc", "sp", "spscan", "spspend", ExtendedKey.Header.xprv, ExtendedKey.Header.xpub, 128, 8332),
TESTNET("testnet", "Testnet3", "testnet3", 111, "mn", 196, "2", "tb", "tsp", "tspscan", "tspspend", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18332),
REGTEST("regtest", "Regtest", "regtest", 111, "mn", 196, "2", "bcrt", "sprt", "tspscan", "tspspend", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 18443),
SIGNET("signet", "Signet", "signet", 111, "mn", 196, "2", "tb", "tsp", "tspscan", "tspspend", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 38332),
TESTNET4("testnet4", "Testnet4", "testnet4", 111, "mn", 196, "2", "tb", "tsp", "tspscan", "tspspend", ExtendedKey.Header.tprv, ExtendedKey.Header.tpub, 239, 48332);
public static final String BLOCK_HEIGHT_PROPERTY = "com.sparrowwallet.blockHeight";
private static final Network[] CANONICAL_VALUES = new Network[]{MAINNET, TESTNET, REGTEST, SIGNET};
Network(String name, String displayName, String home, int p2pkhAddressHeader, String p2pkhAddressPrefix, int p2shAddressHeader, String p2shAddressPrefix, String bech32AddressHrp, String spAddressHrp, ExtendedKey.Header xprvHeader, ExtendedKey.Header xpubHeader, int dumpedPrivateKeyHeader, int defaultPort) {
Network(String name, String displayName, String home, int p2pkhAddressHeader, String p2pkhAddressPrefix, int p2shAddressHeader, String p2shAddressPrefix, String bech32AddressHrp, String spAddressHrp, String spScanKeyHrp, String spSpendKeyHrp, ExtendedKey.Header xprvHeader, ExtendedKey.Header xpubHeader, int dumpedPrivateKeyHeader, int defaultPort) {
this.name = name;
this.displayName = displayName;
this.home = home;
@ -22,6 +22,8 @@ public enum Network {
this.p2shAddressPrefix = p2shAddressPrefix;
this.bech32AddressHrp = bech32AddressHrp;
this.spAddressHrp = spAddressHrp;
this.spScanKeyHrp = spScanKeyHrp;
this.spSpendKeyHrp = spSpendKeyHrp;
this.xprvHeader = xprvHeader;
this.xpubHeader = xpubHeader;
this.dumpedPrivateKeyHeader = dumpedPrivateKeyHeader;
@ -37,6 +39,8 @@ public enum Network {
private final String p2shAddressPrefix;
private final String bech32AddressHrp;
private final String spAddressHrp;
private final String spScanKeyHrp;
private final String spSpendKeyHrp;
private final ExtendedKey.Header xprvHeader;
private final ExtendedKey.Header xpubHeader;
private final int dumpedPrivateKeyHeader;
@ -76,6 +80,14 @@ public enum Network {
return spAddressHrp;
}
public String getSilentPaymentsKeyHrp() {
return spScanKeyHrp;
}
public String getSilentPaymentsSpendKeyHrp() {
return spSpendKeyHrp;
}
public ExtendedKey.Header getXprvHeader() {
return xprvHeader;
}

View File

@ -162,7 +162,7 @@ public class OutputDescriptor {
}
public boolean isCosigner() {
return !isMultisig() && scriptType.isAllowed(PolicyType.MULTI);
return !isMultisig() && scriptType.isAllowed(PolicyType.MULTI_HD);
}
public ExtendedKey getSingletonExtendedPublicKey() {
@ -266,7 +266,7 @@ public class OutputDescriptor {
public Wallet toWallet() {
Wallet wallet = new Wallet();
wallet.setPolicyType(isMultisig() || isCosigner() ? PolicyType.MULTI : PolicyType.SINGLE);
wallet.setPolicyType(isMultisig() || isCosigner() ? PolicyType.MULTI_HD : PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType);
for(Map.Entry<ExtendedKey,KeyDerivation> extKeyEntry : extendedPublicKeys.entrySet()) {
@ -318,7 +318,7 @@ public class OutputDescriptor {
keystore.setExtendedPublicKey(extendedKey);
setKeystoreLabel(keystore);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(isCosigner() ? PolicyType.MULTI : PolicyType.SINGLE, wallet.getScriptType(), wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(isCosigner() ? PolicyType.MULTI_HD : PolicyType.SINGLE_HD, wallet.getScriptType(), wallet.getKeystores(), 1));
return wallet;
}

View File

@ -135,7 +135,7 @@ public class Bip322 {
}
private static void checkScriptType(ScriptType scriptType) {
if(!scriptType.isAllowed(PolicyType.SINGLE)) {
if(!scriptType.isAllowed(PolicyType.SINGLE_HD)) {
throw new UnsupportedOperationException("Only singlesig addresses are currently supported");
}

View File

@ -4,8 +4,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Miniscript {
private static final Pattern SINGLE_PATTERN = Pattern.compile("pkh?\\(");
private static final Pattern KEYHASH_PATTERN = Pattern.compile("pkh?\\(");
private static final Pattern TAPROOT_PATTERN = Pattern.compile("tr\\(");
private static final Pattern SILENT_PAYMENTS_PATTERN = Pattern.compile("sp\\(");
private static final Pattern MULTI_PATTERN = Pattern.compile("multi\\((\\d+)");
private String script;
@ -23,7 +24,7 @@ public class Miniscript {
}
public int getNumSignaturesRequired() {
Matcher singleMatcher = SINGLE_PATTERN.matcher(script);
Matcher singleMatcher = KEYHASH_PATTERN.matcher(script);
if(singleMatcher.find()) {
return 1;
}
@ -33,6 +34,11 @@ public class Miniscript {
return 1;
}
Matcher silentPaymentsMatcher = SILENT_PAYMENTS_PATTERN.matcher(script);
if(silentPaymentsMatcher.find()) {
return 1;
}
Matcher multiMatcher = MULTI_PATTERN.matcher(script);
if(multiMatcher.find()) {
String threshold = multiMatcher.group(1);

View File

@ -41,11 +41,11 @@ public class Policy extends Persistable {
}
public static Policy getPolicy(PolicyType policyType, ScriptType scriptType, List<Keystore> keystores, Integer threshold) {
if(SINGLE.equals(policyType)) {
if(SINGLE_HD.equals(policyType)) {
return new Policy(new Miniscript(scriptType.getDescriptor() + keystores.get(0).getScriptName() + scriptType.getCloseDescriptor()));
}
if(MULTI.equals(policyType)) {
if(MULTI_HD.equals(policyType)) {
StringBuilder builder = new StringBuilder();
builder.append(scriptType.getDescriptor());
builder.append(MULTISIG.getDescriptor());
@ -58,6 +58,10 @@ public class Policy extends Persistable {
return new Policy(new Miniscript(builder.toString()));
}
if(SINGLE_SP.equals(policyType)) {
return new Policy(new Miniscript("sp(" + keystores.get(0).getScriptName() + ")"));
}
throw new PolicyException("No standard policy for " + policyType + " policy with script type " + scriptType);
}

View File

@ -5,13 +5,15 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
import static com.sparrowwallet.drongo.protocol.ScriptType.*;
public enum PolicyType {
SINGLE("Single Signature", P2WPKH), MULTI("Multi Signature", P2WSH), CUSTOM("Custom", P2WSH);
SINGLE_HD("Single Signature HD", "Single Signature HD", P2WPKH), MULTI_HD("Multi Signature HD", "Multi Signature HD", P2WSH), SINGLE_SP("Single Signature SP", "Single Signature SP (Silent Payments)", P2TR);
private String name;
private ScriptType defaultScriptType;
private final String name;
private final String description;
private final ScriptType defaultScriptType;
PolicyType(String name, ScriptType defaultScriptType) {
PolicyType(String name, String description, ScriptType defaultScriptType) {
this.name = name;
this.description = description;
this.defaultScriptType = defaultScriptType;
}
@ -19,6 +21,10 @@ public enum PolicyType {
return name;
}
public String getDescription() {
return description;
}
public ScriptType getDefaultScriptType() {
return defaultScriptType;
}

View File

@ -133,7 +133,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(SINGLE);
return List.of(SINGLE_HD);
}
},
P2PKH("P2PKH", "Legacy (P2PKH)", "m/44'/0'/0'") {
@ -251,7 +251,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(SINGLE);
return List.of(SINGLE_HD);
}
},
MULTISIG("Bare Multisig", "Bare Multisig", "m/44'/0'/0'") {
@ -442,7 +442,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(MULTI);
return List.of(MULTI_HD);
}
},
P2SH("P2SH", "Legacy (P2SH)", "m/45'") {
@ -572,7 +572,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(MULTI);
return List.of(MULTI_HD);
}
},
P2SH_P2WPKH("P2SH-P2WPKH", "Nested Segwit (P2SH-P2WPKH)", "m/49'/0'/0'") {
@ -680,7 +680,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(SINGLE);
return List.of(SINGLE_HD);
}
},
P2SH_P2WSH("P2SH-P2WSH", "Nested Segwit (P2SH-P2WSH)", "m/48'/0'/0'/1'") {
@ -786,7 +786,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(MULTI, CUSTOM);
return List.of(MULTI_HD);
}
},
P2WPKH("P2WPKH", "Native Segwit (P2WPKH)", "m/84'/0'/0'") {
@ -896,7 +896,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(SINGLE);
return List.of(SINGLE_HD);
}
},
P2WSH("P2WSH", "Native Segwit (P2WSH)", "m/48'/0'/0'/2'") {
@ -1012,7 +1012,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(MULTI, CUSTOM);
return List.of(MULTI_HD);
}
},
P2TR("P2TR", "Taproot (P2TR)", "m/86'/0'/0'") {
@ -1132,7 +1132,7 @@ public enum ScriptType {
@Override
public List<PolicyType> getAllowedPolicyTypes() {
return List.of(SINGLE);
return List.of(SINGLE_HD, SINGLE_SP);
}
},
P2A("P2A", "Anchor (P2A)", "m/86'/0'/0'") {

View File

@ -1,12 +1,17 @@
package com.sparrowwallet.drongo.silentpayments;
import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.policy.Policy;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.Bech32;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.*;
import java.util.Arrays;
public class SilentPaymentScanAddress extends SilentPaymentAddress {
public SilentPaymentScanAddress(ECKey scanPrivateKey, ECKey spendPublicKey) {
super(scanPrivateKey, spendPublicKey);
@ -35,11 +40,11 @@ public class SilentPaymentScanAddress extends SilentPaymentAddress {
public static SilentPaymentScanAddress from(DeterministicSeed deterministicSeed, int account) throws MnemonicException {
Wallet spWallet = new Wallet();
spWallet.setPolicyType(PolicyType.SINGLE);
spWallet.setPolicyType(PolicyType.SINGLE_HD);
spWallet.setScriptType(ScriptType.P2WPKH);
Keystore spKeystore = Keystore.fromSeed(deterministicSeed, KeyDerivation.getBip352Derivation(account));
spWallet.getKeystores().add(spKeystore);
spWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, spWallet.getKeystores(), 1));
spWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, spWallet.getKeystores(), 1));
WalletNode spendNode = new WalletNode(spWallet, "m/0'/0");
WalletNode scanNode = new WalletNode(spWallet, "m/1'/0");
@ -50,4 +55,27 @@ public class SilentPaymentScanAddress extends SilentPaymentAddress {
public static SilentPaymentScanAddress from(ECKey scanPrivateKey, ECKey spendPublicKey) {
return new SilentPaymentScanAddress(scanPrivateKey, spendPublicKey);
}
public SilentPaymentScanAddress copy() {
return new SilentPaymentScanAddress(getScanKey(), getSpendKey());
}
public String toKeyString() {
return Bech32.encode(Network.get().getSilentPaymentsKeyHrp(), 0, Bech32.Encoding.BECH32M, toBytes());
}
public byte[] toBytes() {
return Utils.concat(getScanKey().getPrivKeyBytes(), getSpendKey().getPubKey(true));
}
public static SilentPaymentScanAddress fromBytes(byte[] bytes) {
if(bytes == null || bytes.length != 65) {
throw new IllegalArgumentException("Invalid silent payments scan address serialization, must be 65 bytes long");
}
ECKey scanKey = ECKey.fromPrivate(Arrays.copyOfRange(bytes, 0, 32));
ECKey spendKey = ECKey.fromPublicOnly(Arrays.copyOfRange(bytes, 32, 65));
return new SilentPaymentScanAddress(scanKey, spendKey);
}
}

View File

@ -10,8 +10,6 @@ import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* This is a special wallet that is used solely to finalize a fully signed PSBT by reading from the partial signatures and UTXO scriptPubKey
@ -67,7 +65,7 @@ public class FinalizingPSBTWallet extends Wallet {
setGapLimit(0);
purposeNode.setChildren(new TreeSet<>());
setPolicyType(numSignatures == 1 ? PolicyType.SINGLE : PolicyType.MULTI);
setPolicyType(numSignatures == 1 ? PolicyType.SINGLE_HD : PolicyType.MULTI_HD);
}
@Override

View File

@ -9,11 +9,11 @@ import com.sparrowwallet.drongo.bip47.PaymentCode;
import com.sparrowwallet.drongo.crypto.*;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.silentpayments.SilentPaymentScanAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Keystore extends Persistable {
@ -28,6 +28,7 @@ public class Keystore extends Persistable {
private KeyDerivation keyDerivation;
private ExtendedKey extendedPublicKey;
private PaymentCode externalPaymentCode;
private SilentPaymentScanAddress silentPaymentScanAddress;
private byte[] deviceRegistration;
private MasterPrivateExtendedKey masterPrivateExtendedKey;
private DeterministicSeed seed;
@ -106,6 +107,14 @@ public class Keystore extends Persistable {
this.externalPaymentCode = paymentCode;
}
public SilentPaymentScanAddress getSilentPaymentScanAddress() {
return silentPaymentScanAddress;
}
public void setSilentPaymentScanAddress(SilentPaymentScanAddress silentPaymentScanAddress) {
this.silentPaymentScanAddress = silentPaymentScanAddress;
}
public byte[] getDeviceRegistration() {
return deviceRegistration;
}
@ -310,8 +319,8 @@ public class Keystore extends Persistable {
throw new InvalidKeystoreException("No key derivation specified");
}
if(extendedPublicKey == null) {
throw new InvalidKeystoreException("No extended public key specified");
if(extendedPublicKey == null && silentPaymentScanAddress == null) {
throw new InvalidKeystoreException("No extended public key or silent payment scan address specified");
}
if(label.isEmpty()) {
@ -385,6 +394,9 @@ public class Keystore extends Persistable {
if(bip47ExtendedPrivateKey != null) {
copy.setBip47ExtendedPrivateKey(bip47ExtendedPrivateKey.copy());
}
if(silentPaymentScanAddress != null) {
copy.setSilentPaymentScanAddress(silentPaymentScanAddress.copy());
}
return copy;
}
@ -416,12 +428,17 @@ public class Keystore extends Persistable {
keystore.setKeyDerivation(new KeyDerivation(masterFingerprint, KeyDerivation.writePath(derivation)));
keystore.setExtendedPublicKey(ExtendedKey.fromDescriptor(xpub.toString()));
int account = ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE).stream()
int account = ScriptType.getScriptTypesForPolicyType(PolicyType.SINGLE_HD).stream()
.mapToInt(scriptType -> scriptType.getAccount(keystore.getKeyDerivation().getDerivationPath())).filter(idx -> idx > -1).findFirst().orElse(0);
List<ChildNumber> bip47Derivation = KeyDerivation.getBip47Derivation(account);
DeterministicKey bip47Key = xprv.getKey(bip47Derivation);
ExtendedKey bip47ExtendedPrivateKey = new ExtendedKey(bip47Key, bip47Key.getParentFingerprint(), bip47Derivation.get(bip47Derivation.size() - 1));
keystore.setBip47ExtendedPrivateKey(ExtendedKey.fromDescriptor(bip47ExtendedPrivateKey.toString()));
DeterministicKey scanKey = xprv.getKey(KeyDerivation.getBip352ScanDerivation(derivation));
DeterministicKey spendKey = xprv.getKey(KeyDerivation.getBip352SpendDerivation(derivation));
SilentPaymentScanAddress spScanAddress = new SilentPaymentScanAddress(ECKey.fromPrivate(scanKey.getPrivKey()), ECKey.fromPublicOnly(spendKey));
keystore.setSilentPaymentScanAddress(spScanAddress);
}
public boolean isEncrypted() {

View File

@ -187,7 +187,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
public Wallet addChildWallet(PaymentCode externalPaymentCode, ScriptType childScriptType, String label) {
if(policyType != PolicyType.SINGLE) {
if(policyType != PolicyType.SINGLE_HD) {
throw new IllegalStateException("Cannot add payment code wallet to " + policyType.getName() + " wallet");
}
@ -202,7 +202,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
Wallet childWallet = new Wallet(childScriptType + "-" + externalPaymentCode.toString());
childWallet.setLabel(label);
childWallet.setPolicyType(PolicyType.SINGLE);
childWallet.setPolicyType(PolicyType.SINGLE_HD);
childWallet.setScriptType(childScriptType);
childWallet.setGapLimit(5);
@ -217,7 +217,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
keystore.setExtendedPublicKey(new ExtendedKey(pubKey, keystore.getBip47ExtendedPrivateKey().getParentFingerprint(), derivation.get(derivation.size() - 1)));
childWallet.getKeystores().add(keystore);
childWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, scriptType, childWallet.getKeystores(), 1));
childWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, scriptType, childWallet.getKeystores(), 1));
childWallet.setMasterWallet(this);
getChildWallets().add(childWallet);
@ -251,7 +251,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
public boolean hasPaymentCode() {
return getKeystores().size() == 1 && getKeystores().get(0).getBip47ExtendedPrivateKey() != null && policyType == PolicyType.SINGLE
return getKeystores().size() == 1 && getKeystores().get(0).getBip47ExtendedPrivateKey() != null && policyType == PolicyType.SINGLE_HD
&& PaymentCode.SEGWIT_SCRIPT_TYPES.contains(scriptType);
}
@ -266,7 +266,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
public Wallet getNotificationWallet() {
if(isMasterWallet() && hasPaymentCode()) {
Wallet notificationWallet = new Wallet();
notificationWallet.setPolicyType(PolicyType.SINGLE);
notificationWallet.setPolicyType(PolicyType.SINGLE_HD);
notificationWallet.setScriptType(ScriptType.P2PKH);
notificationWallet.setGapLimit(0);
@ -280,7 +280,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
keystore.setBip47ExtendedPrivateKey(masterKeystore.getBip47ExtendedPrivateKey());
notificationWallet.getKeystores().add(keystore);
notificationWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, notificationWallet.getKeystores(), 1));
notificationWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2PKH, notificationWallet.getKeystores(), 1));
return notificationWallet;
}
@ -322,7 +322,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
public boolean canSendSilentPayments() {
return getKeystores().size() == 1 && policyType == PolicyType.SINGLE && SilentPayment.VALID_INPUT_SCRIPT_TYPES.contains(scriptType);
return getKeystores().size() == 1 && (policyType == PolicyType.SINGLE_HD || policyType == PolicyType.SINGLE_SP) && SilentPayment.VALID_INPUT_SCRIPT_TYPES.contains(scriptType);
}
public StandardAccount getStandardAccountType() {
@ -661,10 +661,8 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
public ECKey getPubKey(WalletNode node) {
if(policyType == PolicyType.MULTI) {
if(policyType == PolicyType.MULTI_HD) {
throw new IllegalStateException("Attempting to retrieve a single key for a multisig policy wallet");
} else if(policyType == PolicyType.CUSTOM) {
throw new UnsupportedOperationException("Cannot determine a public key for a custom policy");
}
Keystore keystore = getKeystores().get(0);
@ -672,20 +670,18 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
public List<ECKey> getPubKeys(WalletNode node) {
if(policyType == PolicyType.SINGLE) {
if(policyType == PolicyType.SINGLE_HD || policyType == PolicyType.SINGLE_SP) {
throw new IllegalStateException("Attempting to retrieve multiple keys for a singlesig policy wallet");
} else if(policyType == PolicyType.CUSTOM) {
throw new UnsupportedOperationException("Cannot determine public keys for a custom policy");
}
return getKeystores().stream().map(keystore -> keystore.getPubKey(node)).collect(Collectors.toList());
}
public Address getAddress(WalletNode node) {
if(policyType == PolicyType.SINGLE) {
if(policyType == PolicyType.SINGLE_HD || policyType == PolicyType.SINGLE_SP) {
ECKey pubKey = node.getPubKey();
return scriptType.getAddress(pubKey);
} else if(policyType == PolicyType.MULTI) {
} else if(policyType == PolicyType.MULTI_HD) {
List<ECKey> pubKeys = node.getPubKeys();
Script script = ScriptType.MULTISIG.getOutputScript(defaultPolicy.getNumSignaturesRequired(), pubKeys);
return scriptType.getAddress(script);
@ -695,10 +691,10 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
public Script getOutputScript(WalletNode node) {
if(policyType == PolicyType.SINGLE) {
if(policyType == PolicyType.SINGLE_HD || policyType == PolicyType.SINGLE_SP) {
ECKey pubKey = node.getPubKey();
return scriptType.getOutputScript(pubKey);
} else if(policyType == PolicyType.MULTI) {
} else if(policyType == PolicyType.MULTI_HD) {
List<ECKey> pubKeys = node.getPubKeys();
Script script = ScriptType.MULTISIG.getOutputScript(defaultPolicy.getNumSignaturesRequired(), pubKeys);
return scriptType.getOutputScript(script);
@ -708,10 +704,10 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
public String getOutputDescriptor(WalletNode node) {
if(policyType == PolicyType.SINGLE) {
if(policyType == PolicyType.SINGLE_HD || policyType == PolicyType.SINGLE_SP) {
ECKey pubKey = node.getPubKey();
return scriptType.getOutputDescriptor(pubKey);
} else if(policyType == PolicyType.MULTI) {
} else if(policyType == PolicyType.MULTI_HD) {
List<ECKey> pubKeys = node.getPubKeys();
Script script = ScriptType.MULTISIG.getOutputScript(defaultPolicy.getNumSignaturesRequired(), pubKeys);
return scriptType.getOutputDescriptor(script);
@ -1004,11 +1000,11 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
TransactionOutput prevTxOut = transaction.addOutput(1L, receiveNode.getAddress());
TransactionInput txInput = null;
if(getPolicyType().equals(PolicyType.SINGLE)) {
if(getPolicyType().equals(PolicyType.SINGLE_HD) || getPolicyType().equals(PolicyType.SINGLE_SP)) {
ECKey pubKey = receiveNode.getPubKey();
TransactionSignature signature = TransactionSignature.dummy(getScriptType().getSignatureType());
txInput = getScriptType().addSpendingInput(transaction, prevTxOut, pubKey, signature);
} else if(getPolicyType().equals(PolicyType.MULTI)) {
} else if(getPolicyType().equals(PolicyType.MULTI_HD)) {
List<ECKey> pubKeys = receiveNode.getPubKeys();
int threshold = getDefaultPolicy().getNumSignaturesRequired();
Map<ECKey, TransactionSignature> pubKeySignatures = new TreeMap<>(new ECKey.LexicographicECKeyComparator());
@ -1231,10 +1227,10 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
public static TransactionInput addDummySpendingInput(Transaction transaction, WalletNode walletNode, TransactionOutput prevTxOut) {
Wallet signingWallet = walletNode.getWallet();
if(signingWallet.getPolicyType().equals(PolicyType.SINGLE)) {
if(signingWallet.getPolicyType().equals(PolicyType.SINGLE_HD) || signingWallet.getPolicyType().equals(PolicyType.SINGLE_SP)) {
ECKey pubKey = walletNode.getPubKey();
return signingWallet.getScriptType().addSpendingInput(transaction, prevTxOut, pubKey, TransactionSignature.dummy(signingWallet.getScriptType().getSignatureType()));
} else if(signingWallet.getPolicyType().equals(PolicyType.MULTI)) {
} else if(signingWallet.getPolicyType().equals(PolicyType.MULTI_HD)) {
List<ECKey> pubKeys = walletNode.getPubKeys();
int threshold = signingWallet.getDefaultPolicy().getNumSignaturesRequired();
Map<ECKey, TransactionSignature> pubKeySignatures = new TreeMap<>(new ECKey.LexicographicECKeyComparator());
@ -1585,10 +1581,6 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
private WalletNode matchDerivation(KeyDerivation keyDerivation, Script scriptPubKey) {
if(policyType == PolicyType.CUSTOM) {
return null;
}
for(Keystore keystore : getKeystores()) {
ECKey derivedKey = keystore.getPubKeyForDerivation(keyDerivation);
if(derivedKey == null) {
@ -1807,7 +1799,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
Transaction transaction = new Transaction();
TransactionInput finalizedTxInput;
if(getPolicyType().equals(PolicyType.SINGLE)) {
if(getPolicyType().equals(PolicyType.SINGLE_HD) || getPolicyType().equals(PolicyType.SINGLE_SP)) {
ECKey pubKey = signingNode.getPubKey();
TransactionSignature transactionSignature = psbtInput.isTaproot() ? psbtInput.getTapKeyPathSignature() : psbtInput.getPartialSignature(pubKey);
if(transactionSignature == null) {
@ -1815,7 +1807,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
}
finalizedTxInput = signingNode.getWallet().getScriptType().addSpendingInput(transaction, utxo, pubKey, transactionSignature);
} else if(getPolicyType().equals(PolicyType.MULTI)) {
} else if(getPolicyType().equals(PolicyType.MULTI_HD)) {
List<ECKey> pubKeys = signingNode.getPubKeys();
Map<ECKey, TransactionSignature> pubKeySignatures = new TreeMap<>(new ECKey.LexicographicECKeyComparator());
@ -1950,14 +1942,22 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
throw new InvalidWalletException("Cannot determine number of required signatures to sign a transaction");
}
if(policyType.equals(PolicyType.SINGLE) && (numSigs != 1 || keystores.size() != 1)) {
if((policyType.equals(PolicyType.SINGLE_HD) || policyType.equals(PolicyType.SINGLE_SP)) && (numSigs != 1 || keystores.size() != 1)) {
throw new InvalidWalletException(policyType + " wallet needs " + numSigs + " and has " + keystores.size() + " keystores");
}
if(policyType.equals(PolicyType.MULTI) && (numSigs < 1 || numSigs > keystores.size())) {
if(policyType.equals(PolicyType.MULTI_HD) && (numSigs < 1 || numSigs > keystores.size())) {
throw new InvalidWalletException(policyType + " wallet needs " + numSigs + " and has " + keystores.size() + " keystores");
}
if(policyType.equals(PolicyType.SINGLE_HD) && keystores.getFirst().getExtendedPublicKey() == null) {
throw new InvalidWalletException(policyType + " wallet needs an extended public key");
}
if(policyType.equals(PolicyType.SINGLE_SP) && keystores.getFirst().getSilentPaymentScanAddress() == null) {
throw new InvalidWalletException(policyType + " wallet needs a silent payment scan address");
}
if(containsDuplicateKeystoreLabels()) {
throw new InvalidWalletException("Wallet keystores have duplicate labels");
}

View File

@ -92,22 +92,22 @@ public class PaymentCodeTest {
List<String> receiveWords = bip39MnemonicCode.toMnemonic(receiveEntropy);
DeterministicSeed receiveSeed = new DeterministicSeed(receiveWords, "", 0, DeterministicSeed.Type.BIP39);
Wallet receiveWallet = new Wallet();
receiveWallet.setPolicyType(PolicyType.SINGLE);
receiveWallet.setPolicyType(PolicyType.SINGLE_HD);
receiveWallet.setScriptType(ScriptType.P2WPKH);
Keystore receiveKeystore = Keystore.fromSeed(receiveSeed, receiveWallet.getScriptType().getDefaultDerivation());
receiveWallet.getKeystores().add(receiveKeystore);
receiveWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, receiveWallet.getKeystores(), 1));
receiveWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, receiveWallet.getKeystores(), 1));
byte[] sendEntropy = new byte[128];
secureRandom.nextBytes(sendEntropy);
List<String> sendWords = bip39MnemonicCode.toMnemonic(sendEntropy);
DeterministicSeed sendSeed = new DeterministicSeed(sendWords, "pp", 0, DeterministicSeed.Type.BIP39);
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Keystore sendKeystore = Keystore.fromSeed(sendSeed, sendWallet.getScriptType().getDefaultDerivation());
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
PaymentCode paymentCode = sendWallet.getPaymentCode();
PaymentCode externalPaymentCode = receiveWallet.getPaymentCode();
@ -165,10 +165,10 @@ public class PaymentCodeTest {
public void testChildWallet() throws MnemonicException, InvalidPaymentCodeException {
DeterministicSeed aliceSeed = new DeterministicSeed("response seminar brave tip suit recall often sound stick owner lottery motion", "", 0, DeterministicSeed.Type.BIP39);
Wallet aliceWallet = new Wallet();
aliceWallet.setPolicyType(PolicyType.SINGLE);
aliceWallet.setPolicyType(PolicyType.SINGLE_HD);
aliceWallet.setScriptType(ScriptType.P2PKH);
aliceWallet.getKeystores().add(Keystore.fromSeed(aliceSeed, aliceWallet.getScriptType().getDefaultDerivation()));
aliceWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, aliceWallet.getKeystores(), 1));
aliceWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2PKH, aliceWallet.getKeystores(), 1));
PaymentCode paymentCodeBob = new PaymentCode("PM8TJS2JxQ5ztXUpBBRnpTbcUXbUHy2T1abfrb3KkAAtMEGNbey4oumH7Hc578WgQJhPjBxteQ5GHHToTYHE3A1w6p7tU6KSoFmWBVbFGjKPisZDbP97");
@ -193,10 +193,10 @@ public class PaymentCodeTest {
DeterministicSeed bobSeed = new DeterministicSeed("reward upper indicate eight swift arch injury crystal super wrestle already dentist", "", 0, DeterministicSeed.Type.BIP39);
Wallet bobWallet = new Wallet();
bobWallet.setPolicyType(PolicyType.SINGLE);
bobWallet.setPolicyType(PolicyType.SINGLE_HD);
bobWallet.setScriptType(ScriptType.P2PKH);
bobWallet.getKeystores().add(Keystore.fromSeed(bobSeed, bobWallet.getScriptType().getDefaultDerivation()));
bobWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, bobWallet.getKeystores(), 1));
bobWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2PKH, bobWallet.getKeystores(), 1));
Wallet bobBip47Wallet = bobWallet.addChildWallet(paymentCodeAlice, ScriptType.P2PKH, "Bob");
Assertions.assertEquals(paymentCodeBob.toString(), bobBip47Wallet.getKeystores().get(0).getPaymentCode().toString());

View File

@ -18,11 +18,11 @@ public class ECKeyTest {
String words = "absent essay fox snake vast pumpkin height crouch silent bulb excuse razor";
DeterministicSeed seed = new DeterministicSeed(words, "", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2PKH);
Keystore keystore = Keystore.fromSeed(seed, wallet.getScriptType().getDefaultDerivation());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2PKH, wallet.getKeystores(), 1));
WalletNode firstReceive = wallet.getNode(KeyPurpose.RECEIVE).getChildren().iterator().next();
Address address = firstReceive.getAddress();

View File

@ -167,7 +167,7 @@ public class SilentPaymentUtilsTest {
Assertions.assertEquals("3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", Utils.bytesToHex(address.getData()));
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -186,7 +186,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -200,7 +200,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testSimpleSendTwoInputsReversed() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -219,7 +219,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -232,7 +232,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testSimpleSendTwoInputsSameTransaction() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -251,7 +251,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -264,7 +264,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testSimpleSendTwoInputsSameTransactionReversed() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -283,7 +283,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -296,7 +296,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testOutpointOrderingIndex() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -315,7 +315,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -328,7 +328,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testSingleRecipientSamePubKey() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -347,7 +347,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -360,7 +360,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testSingleRecipientTaprootOnlyEvenY() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2TR);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -389,7 +389,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -402,7 +402,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testSingleRecipientTaprootOnlyMixedY() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2TR);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -431,7 +431,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -444,12 +444,12 @@ public class SilentPaymentUtilsTest {
@Test
public void testSingleRecipientTaprootEvenYAndNonTaproot() throws InvalidSilentPaymentException {
Wallet taprootWallet = new Wallet();
taprootWallet.setPolicyType(PolicyType.SINGLE);
taprootWallet.setPolicyType(PolicyType.SINGLE_HD);
taprootWallet.setScriptType(ScriptType.P2TR);
Map<WalletNode, ECKey> taprootPrivateKeys = new LinkedHashMap<>();
Wallet segwitWallet = new Wallet();
segwitWallet.setPolicyType(PolicyType.SINGLE);
segwitWallet.setPolicyType(PolicyType.SINGLE_HD);
segwitWallet.setScriptType(ScriptType.P2WPKH);
Map<WalletNode, ECKey> segwitPrivateKeys = new LinkedHashMap<>();
@ -474,11 +474,11 @@ public class SilentPaymentUtilsTest {
TestKeystore taprootKeystore = new TestKeystore(taprootPrivateKeys);
taprootWallet.getKeystores().add(taprootKeystore);
taprootWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, taprootWallet.getKeystores(), 1));
taprootWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, taprootWallet.getKeystores(), 1));
TestKeystore segwitKeystore = new TestKeystore(segwitPrivateKeys);
segwitWallet.getKeystores().add(segwitKeystore);
segwitWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, segwitWallet.getKeystores(), 1));
segwitWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, segwitWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -491,12 +491,12 @@ public class SilentPaymentUtilsTest {
@Test
public void testSingleRecipientTaprootOddYAndNonTaproot() throws InvalidSilentPaymentException {
Wallet taprootWallet = new Wallet();
taprootWallet.setPolicyType(PolicyType.SINGLE);
taprootWallet.setPolicyType(PolicyType.SINGLE_HD);
taprootWallet.setScriptType(ScriptType.P2TR);
Map<WalletNode, ECKey> taprootPrivateKeys = new LinkedHashMap<>();
Wallet segwitWallet = new Wallet();
segwitWallet.setPolicyType(PolicyType.SINGLE);
segwitWallet.setPolicyType(PolicyType.SINGLE_HD);
segwitWallet.setScriptType(ScriptType.P2WPKH);
Map<WalletNode, ECKey> segwitPrivateKeys = new LinkedHashMap<>();
@ -521,11 +521,11 @@ public class SilentPaymentUtilsTest {
TestKeystore taprootKeystore = new TestKeystore(taprootPrivateKeys);
taprootWallet.getKeystores().add(taprootKeystore);
taprootWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, taprootWallet.getKeystores(), 1));
taprootWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, taprootWallet.getKeystores(), 1));
TestKeystore segwitKeystore = new TestKeystore(segwitPrivateKeys);
segwitWallet.getKeystores().add(segwitKeystore);
segwitWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, segwitWallet.getKeystores(), 1));
segwitWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, segwitWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
List<SilentPayment> silentPayments = List.of(new SilentPayment(silentPaymentAddress, "", 0, false));
@ -538,7 +538,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testMultipleOutputsSameRecipient() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -557,7 +557,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress0 = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
SilentPaymentAddress silentPaymentAddress1 = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
@ -574,7 +574,7 @@ public class SilentPaymentUtilsTest {
@Test
public void testMultipleOutputsMultipleRecipients() throws InvalidSilentPaymentException {
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -593,7 +593,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
SilentPaymentAddress silentPaymentAddress0 = SilentPaymentAddress.from("sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv");
SilentPaymentAddress silentPaymentAddress1 = SilentPaymentAddress.from("sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn");
@ -619,7 +619,7 @@ public class SilentPaymentUtilsTest {
// Expected sum = A (non-zero)
Wallet sendWallet = new Wallet();
sendWallet.setPolicyType(PolicyType.SINGLE);
sendWallet.setPolicyType(PolicyType.SINGLE_HD);
sendWallet.setScriptType(ScriptType.P2WPKH);
Map<HashIndex, WalletNode> utxos = new LinkedHashMap<>();
Map<WalletNode, ECKey> privateKeys = new LinkedHashMap<>();
@ -647,7 +647,7 @@ public class SilentPaymentUtilsTest {
TestKeystore sendKeystore = new TestKeystore(privateKeys);
sendWallet.getKeystores().add(sendKeystore);
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
sendWallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, sendWallet.getKeystores(), 1));
ECKey summedKey = SilentPaymentUtils.getSummedPrivateKey(utxos.values());
Assertions.assertEquals("a6df6a0bb448992a301df4258e06a89fe7cf7146f59ac3bd5ff26083acb22ceb", Utils.bytesToHex(summedKey.getPrivKeyBytes()));

View File

@ -16,27 +16,27 @@ public class PolicyTest {
Keystore keystore2 = new Keystore("Keystore 2");
Keystore keystore3 = new Keystore("Keystore 3");
Policy policy = Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, List.of(keystore1), 1);
Policy policy = Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2PKH, List.of(keystore1), 1);
Assertions.assertEquals("pkh(keystore1)", policy.getMiniscript().toString().toLowerCase(Locale.ROOT));
Assertions.assertEquals(1, policy.getNumSignaturesRequired());
Policy policy2 = Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2SH_P2WPKH, List.of(keystore1), 1);
Policy policy2 = Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2SH_P2WPKH, List.of(keystore1), 1);
Assertions.assertEquals("sh(wpkh(keystore1))", policy2.getMiniscript().toString().toLowerCase(Locale.ROOT));
Assertions.assertEquals(1, policy2.getNumSignaturesRequired());
Policy policy3 = Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, List.of(keystore1), 1);
Policy policy3 = Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, List.of(keystore1), 1);
Assertions.assertEquals("wpkh(keystore1)", policy3.getMiniscript().toString().toLowerCase(Locale.ROOT));
Assertions.assertEquals(1, policy3.getNumSignaturesRequired());
Policy policy4 = Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH, List.of(keystore1, keystore2, keystore3), 2);
Policy policy4 = Policy.getPolicy(PolicyType.MULTI_HD, ScriptType.P2SH, List.of(keystore1, keystore2, keystore3), 2);
Assertions.assertEquals("sh(sortedmulti(2,keystore1,keystore2,keystore3))", policy4.getMiniscript().toString().toLowerCase(Locale.ROOT));
Assertions.assertEquals(2, policy4.getNumSignaturesRequired());
Policy policy5 = Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH_P2WSH, List.of(keystore1, keystore2, keystore3), 2);
Policy policy5 = Policy.getPolicy(PolicyType.MULTI_HD, ScriptType.P2SH_P2WSH, List.of(keystore1, keystore2, keystore3), 2);
Assertions.assertEquals("sh(wsh(sortedmulti(2,keystore1,keystore2,keystore3)))", policy5.getMiniscript().toString().toLowerCase(Locale.ROOT));
Assertions.assertEquals(2, policy5.getNumSignaturesRequired());
Policy policy6 = Policy.getPolicy(PolicyType.MULTI, ScriptType.P2WSH, List.of(keystore1, keystore2, keystore3), 2);
Policy policy6 = Policy.getPolicy(PolicyType.MULTI_HD, ScriptType.P2WSH, List.of(keystore1, keystore2, keystore3), 2);
Assertions.assertEquals("wsh(sortedmulti(2,keystore1,keystore2,keystore3))", policy6.getMiniscript().toString().toLowerCase(Locale.ROOT));
Assertions.assertEquals(2, policy6.getNumSignaturesRequired());
}

View File

@ -22,11 +22,11 @@ public class WalletTest {
String words = "absent essay fox snake vast pumpkin height crouch silent bulb excuse razor";
DeterministicSeed seed = new DeterministicSeed(words, "pp", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2PKH);
Keystore keystore = Keystore.fromSeed(seed, wallet.getScriptType().getDefaultDerivation());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2PKH, wallet.getKeystores(), 1));
KeyDeriver keyDeriver = new Argon2KeyDeriver();
Key key = keyDeriver.deriveKey("pass");
@ -110,11 +110,11 @@ public class WalletTest {
String words = "absent essay fox snake vast pumpkin height crouch silent bulb excuse razor";
DeterministicSeed seed = new DeterministicSeed(words, "pp", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2PKH);
Keystore keystore = Keystore.fromSeed(seed, wallet.getScriptType().getDefaultDerivation());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2PKH, wallet.getKeystores(), 1));
WalletNode receive0 = new WalletNode(wallet, KeyPurpose.RECEIVE, 0);
Assertions.assertEquals("12kTQjuWDp7Uu6PwY6CsS1KLTt3d1DBHZa", receive0.getAddress().toString());
@ -127,11 +127,11 @@ public class WalletTest {
String words = "absent essay fox snake vast pumpkin height crouch silent bulb excuse razor";
DeterministicSeed seed = new DeterministicSeed(words, "pp", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2SH_P2WPKH);
Keystore keystore = Keystore.fromSeed(seed, wallet.getScriptType().getDefaultDerivation());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2SH_P2WPKH, wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2SH_P2WPKH, wallet.getKeystores(), 1));
WalletNode receive0 = new WalletNode(wallet, KeyPurpose.RECEIVE, 0);
Assertions.assertEquals("3NZLE4TntsjtcZ5MbrfxwtYo9meBVybVQj", receive0.getAddress().toString());
@ -144,11 +144,11 @@ public class WalletTest {
String words = "absent essay fox snake vast pumpkin height crouch silent bulb excuse razor";
DeterministicSeed seed = new DeterministicSeed(words, "pp", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2WPKH);
Keystore keystore = Keystore.fromSeed(seed, wallet.getScriptType().getDefaultDerivation());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, wallet.getKeystores(), 1));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, ScriptType.P2WPKH, wallet.getKeystores(), 1));
WalletNode receive0 = new WalletNode(wallet, KeyPurpose.RECEIVE, 0);
Assertions.assertEquals("bc1quvxdut936uswuxwxrk6nvjmgwxh463r0fjwn55", receive0.getAddress().toString());
@ -165,7 +165,7 @@ public class WalletTest {
DeterministicSeed seed2 = new DeterministicSeed(words2, "", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.MULTI);
wallet.setPolicyType(PolicyType.MULTI_HD);
wallet.setScriptType(ScriptType.P2SH);
Keystore keystore = Keystore.fromSeed(seed, ScriptType.P2PKH.getDefaultDerivation());
Assertions.assertEquals("xprv9s21ZrQH143K4G3jeUxf7h93qLeinXNULjjaef1yZFXpoc5D16iHEFkgJ7ThkWzAEBwNNwyJFtrVhJVJRjCc9ew76JrgsVoXT4VYHJBbbSV", keystore.getExtendedMasterPrivateKey().toString());
@ -175,7 +175,7 @@ public class WalletTest {
Assertions.assertEquals("xprv9s21ZrQH143K4FNcBwXNXfzVNskpoRS7cf4jQTLrhbPkhhXp8hz4QRXT62HziiHziM3Pxyd2Qx3UQkoRpcDu2BauuJJRdyrduXBJGgjAgFx", keystore2.getExtendedMasterPrivateKey().toString());
Assertions.assertEquals("xpub6ChqMsFBYpJiJYzcJgEvddHtbZr1mTaE1o4RbhFRBAYVxN8SScGb9kjwkXtM33JKejR16gBZhNbkV14AccetR5u2McnCgTCpDBfa8hee9v8", keystore2.getExtendedPublicKey().toString());
wallet.getKeystores().add(keystore2);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH, wallet.getKeystores(), 2));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI_HD, ScriptType.P2SH, wallet.getKeystores(), 2));
WalletNode receive0 = new WalletNode(wallet, KeyPurpose.RECEIVE, 0);
Assertions.assertEquals("38kq6yz4VcYymTExQPY3gppbz38mtPLveK", receive0.getAddress().toString());
@ -192,7 +192,7 @@ public class WalletTest {
DeterministicSeed seed2 = new DeterministicSeed(words2, "", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.MULTI);
wallet.setPolicyType(PolicyType.MULTI_HD);
wallet.setScriptType(ScriptType.P2SH_P2WSH);
Keystore keystore = Keystore.fromSeed(seed, ScriptType.P2PKH.getDefaultDerivation());
Assertions.assertEquals("xprv9s21ZrQH143K4G3jeUxf7h93qLeinXNULjjaef1yZFXpoc5D16iHEFkgJ7ThkWzAEBwNNwyJFtrVhJVJRjCc9ew76JrgsVoXT4VYHJBbbSV", keystore.getExtendedMasterPrivateKey().toString());
@ -202,7 +202,7 @@ public class WalletTest {
Assertions.assertEquals("xprv9s21ZrQH143K4FNcBwXNXfzVNskpoRS7cf4jQTLrhbPkhhXp8hz4QRXT62HziiHziM3Pxyd2Qx3UQkoRpcDu2BauuJJRdyrduXBJGgjAgFx", keystore2.getExtendedMasterPrivateKey().toString());
Assertions.assertEquals("xpub6ChqMsFBYpJiJYzcJgEvddHtbZr1mTaE1o4RbhFRBAYVxN8SScGb9kjwkXtM33JKejR16gBZhNbkV14AccetR5u2McnCgTCpDBfa8hee9v8", keystore2.getExtendedPublicKey().toString());
wallet.getKeystores().add(keystore2);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH_P2WSH, wallet.getKeystores(), 2));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI_HD, ScriptType.P2SH_P2WSH, wallet.getKeystores(), 2));
WalletNode receive0 = new WalletNode(wallet, KeyPurpose.RECEIVE, 0);
Assertions.assertEquals("3Mw8xqAHh8g3eBvh7q1UEUmoexqdXDK9Tf", receive0.getAddress().toString());
@ -219,7 +219,7 @@ public class WalletTest {
DeterministicSeed seed2 = new DeterministicSeed(words2, "", 0, DeterministicSeed.Type.BIP39);
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.MULTI);
wallet.setPolicyType(PolicyType.MULTI_HD);
wallet.setScriptType(ScriptType.P2WSH);
Keystore keystore = Keystore.fromSeed(seed, ScriptType.P2PKH.getDefaultDerivation());
Assertions.assertEquals("xprv9s21ZrQH143K4G3jeUxf7h93qLeinXNULjjaef1yZFXpoc5D16iHEFkgJ7ThkWzAEBwNNwyJFtrVhJVJRjCc9ew76JrgsVoXT4VYHJBbbSV", keystore.getExtendedMasterPrivateKey().toString());
@ -229,7 +229,7 @@ public class WalletTest {
Assertions.assertEquals("xprv9s21ZrQH143K4FNcBwXNXfzVNskpoRS7cf4jQTLrhbPkhhXp8hz4QRXT62HziiHziM3Pxyd2Qx3UQkoRpcDu2BauuJJRdyrduXBJGgjAgFx", keystore2.getExtendedMasterPrivateKey().toString());
Assertions.assertEquals("xpub6ChqMsFBYpJiJYzcJgEvddHtbZr1mTaE1o4RbhFRBAYVxN8SScGb9kjwkXtM33JKejR16gBZhNbkV14AccetR5u2McnCgTCpDBfa8hee9v8", keystore2.getExtendedPublicKey().toString());
wallet.getKeystores().add(keystore2);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2WSH, wallet.getKeystores(), 2));
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI_HD, ScriptType.P2WSH, wallet.getKeystores(), 2));
WalletNode receive0 = new WalletNode(wallet, KeyPurpose.RECEIVE, 0);
Assertions.assertEquals("bc1q20e4vm656h5lvmngz9ztz6hjzftvh39yzngqhuqzk8qzj7tqnzaqgclrwc", receive0.getAddress().toString());
@ -240,7 +240,7 @@ public class WalletTest {
@Test
public void testHighDerivationPath() {
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(ScriptType.P2WPKH);
Keystore keystore = new Keystore();
keystore.setKeyDerivation(new KeyDerivation("ffffffff", "m/84'/0'/2147483646'"));