From 3b8677e59bc55bb7459b87a3d7b98eb0ea717bd3 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 14 Apr 2026 15:11:47 +0200 Subject: [PATCH] add initial support for silent payments wallets --- .../sparrowwallet/drongo/KeyDerivation.java | 14 +++++ .../com/sparrowwallet/drongo/Network.java | 24 +++++-- .../drongo/OutputDescriptor.java | 6 +- .../sparrowwallet/drongo/crypto/Bip322.java | 2 +- .../drongo/policy/Miniscript.java | 10 ++- .../sparrowwallet/drongo/policy/Policy.java | 8 ++- .../drongo/policy/PolicyType.java | 14 +++-- .../drongo/protocol/ScriptType.java | 18 +++--- .../SilentPaymentScanAddress.java | 32 +++++++++- .../drongo/wallet/FinalizingPSBTWallet.java | 4 +- .../sparrowwallet/drongo/wallet/Keystore.java | 25 ++++++-- .../sparrowwallet/drongo/wallet/Wallet.java | 62 +++++++++---------- .../drongo/bip47/PaymentCodeTest.java | 16 ++--- .../drongo/crypto/ECKeyTest.java | 4 +- .../SilentPaymentUtilsTest.java | 60 +++++++++--------- .../drongo/wallet/PolicyTest.java | 12 ++-- .../drongo/wallet/WalletTest.java | 30 ++++----- 17 files changed, 213 insertions(+), 128 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/KeyDerivation.java b/src/main/java/com/sparrowwallet/drongo/KeyDerivation.java index 5942a4b..afcf58f 100644 --- a/src/main/java/com/sparrowwallet/drongo/KeyDerivation.java +++ b/src/main/java/com/sparrowwallet/drongo/KeyDerivation.java @@ -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 getBip352ScanDerivation(List derivation) { + List scanDerivation = new ArrayList<>(derivation); + scanDerivation.add(new ChildNumber(1, true)); + scanDerivation.add(new ChildNumber(0, false)); + return Collections.unmodifiableList(scanDerivation); + } + + public static List getBip352SpendDerivation(List derivation) { + List 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); } diff --git a/src/main/java/com/sparrowwallet/drongo/Network.java b/src/main/java/com/sparrowwallet/drongo/Network.java index c426260..a3ba9ec 100644 --- a/src/main/java/com/sparrowwallet/drongo/Network.java +++ b/src/main/java/com/sparrowwallet/drongo/Network.java @@ -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; } diff --git a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java index 78f57e1..7b8f275 100644 --- a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java +++ b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java @@ -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 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; } diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java index b963962..483da5e 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java @@ -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"); } diff --git a/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java b/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java index d92883c..f6af699 100644 --- a/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java +++ b/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java @@ -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); diff --git a/src/main/java/com/sparrowwallet/drongo/policy/Policy.java b/src/main/java/com/sparrowwallet/drongo/policy/Policy.java index 370a111..5afdaca 100644 --- a/src/main/java/com/sparrowwallet/drongo/policy/Policy.java +++ b/src/main/java/com/sparrowwallet/drongo/policy/Policy.java @@ -41,11 +41,11 @@ public class Policy extends Persistable { } public static Policy getPolicy(PolicyType policyType, ScriptType scriptType, List 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); } diff --git a/src/main/java/com/sparrowwallet/drongo/policy/PolicyType.java b/src/main/java/com/sparrowwallet/drongo/policy/PolicyType.java index f3ea5db..f9ffbc1 100644 --- a/src/main/java/com/sparrowwallet/drongo/policy/PolicyType.java +++ b/src/main/java/com/sparrowwallet/drongo/policy/PolicyType.java @@ -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; } diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java index c5fc92e..b7bd030 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java @@ -133,7 +133,7 @@ public enum ScriptType { @Override public List 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 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 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 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 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 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 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 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 getAllowedPolicyTypes() { - return List.of(SINGLE); + return List.of(SINGLE_HD, SINGLE_SP); } }, P2A("P2A", "Anchor (P2A)", "m/86'/0'/0'") { diff --git a/src/main/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentScanAddress.java b/src/main/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentScanAddress.java index 40ab0aa..0724e77 100644 --- a/src/main/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentScanAddress.java +++ b/src/main/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentScanAddress.java @@ -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); + } } diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/FinalizingPSBTWallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/FinalizingPSBTWallet.java index fc7bfe9..767846c 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/FinalizingPSBTWallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/FinalizingPSBTWallet.java @@ -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 diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Keystore.java b/src/main/java/com/sparrowwallet/drongo/wallet/Keystore.java index 280488e..f986864 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Keystore.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Keystore.java @@ -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 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() { diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index b3ed681..b74ee0b 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -187,7 +187,7 @@ public class Wallet extends Persistable implements Comparable { } 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 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 { 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 { } 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 { 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 { 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 { } 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 { } 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 { } public List 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 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 { } 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 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 { } 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 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 { 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 pubKeys = receiveNode.getPubKeys(); int threshold = getDefaultPolicy().getNumSignaturesRequired(); Map pubKeySignatures = new TreeMap<>(new ECKey.LexicographicECKeyComparator()); @@ -1231,10 +1227,10 @@ public class Wallet extends Persistable implements Comparable { 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 pubKeys = walletNode.getPubKeys(); int threshold = signingWallet.getDefaultPolicy().getNumSignaturesRequired(); Map pubKeySignatures = new TreeMap<>(new ECKey.LexicographicECKeyComparator()); @@ -1585,10 +1581,6 @@ public class Wallet extends Persistable implements Comparable { } 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 { 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 { } finalizedTxInput = signingNode.getWallet().getScriptType().addSpendingInput(transaction, utxo, pubKey, transactionSignature); - } else if(getPolicyType().equals(PolicyType.MULTI)) { + } else if(getPolicyType().equals(PolicyType.MULTI_HD)) { List pubKeys = signingNode.getPubKeys(); Map pubKeySignatures = new TreeMap<>(new ECKey.LexicographicECKeyComparator()); @@ -1950,14 +1942,22 @@ public class Wallet extends Persistable implements Comparable { 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"); } diff --git a/src/test/java/com/sparrowwallet/drongo/bip47/PaymentCodeTest.java b/src/test/java/com/sparrowwallet/drongo/bip47/PaymentCodeTest.java index 90cddf1..2aa4fab 100644 --- a/src/test/java/com/sparrowwallet/drongo/bip47/PaymentCodeTest.java +++ b/src/test/java/com/sparrowwallet/drongo/bip47/PaymentCodeTest.java @@ -92,22 +92,22 @@ public class PaymentCodeTest { List 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 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()); diff --git a/src/test/java/com/sparrowwallet/drongo/crypto/ECKeyTest.java b/src/test/java/com/sparrowwallet/drongo/crypto/ECKeyTest.java index acdaf6d..ea8f7d5 100644 --- a/src/test/java/com/sparrowwallet/drongo/crypto/ECKeyTest.java +++ b/src/test/java/com/sparrowwallet/drongo/crypto/ECKeyTest.java @@ -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(); diff --git a/src/test/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentUtilsTest.java b/src/test/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentUtilsTest.java index e4c8a5b..45f2bb3 100644 --- a/src/test/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentUtilsTest.java +++ b/src/test/java/com/sparrowwallet/drongo/silentpayments/SilentPaymentUtilsTest.java @@ -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 utxos = new LinkedHashMap<>(); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 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 taprootPrivateKeys = new LinkedHashMap<>(); Wallet segwitWallet = new Wallet(); - segwitWallet.setPolicyType(PolicyType.SINGLE); + segwitWallet.setPolicyType(PolicyType.SINGLE_HD); segwitWallet.setScriptType(ScriptType.P2WPKH); Map 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 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 taprootPrivateKeys = new LinkedHashMap<>(); Wallet segwitWallet = new Wallet(); - segwitWallet.setPolicyType(PolicyType.SINGLE); + segwitWallet.setPolicyType(PolicyType.SINGLE_HD); segwitWallet.setScriptType(ScriptType.P2WPKH); Map 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 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 utxos = new LinkedHashMap<>(); Map 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 utxos = new LinkedHashMap<>(); Map 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 utxos = new LinkedHashMap<>(); Map 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())); diff --git a/src/test/java/com/sparrowwallet/drongo/wallet/PolicyTest.java b/src/test/java/com/sparrowwallet/drongo/wallet/PolicyTest.java index 9b9557b..3f3008b 100644 --- a/src/test/java/com/sparrowwallet/drongo/wallet/PolicyTest.java +++ b/src/test/java/com/sparrowwallet/drongo/wallet/PolicyTest.java @@ -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()); } diff --git a/src/test/java/com/sparrowwallet/drongo/wallet/WalletTest.java b/src/test/java/com/sparrowwallet/drongo/wallet/WalletTest.java index 4015ea2..6d609ce 100644 --- a/src/test/java/com/sparrowwallet/drongo/wallet/WalletTest.java +++ b/src/test/java/com/sparrowwallet/drongo/wallet/WalletTest.java @@ -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'"));