add policy type to all keystore import interfaces and factory methods for explicit keystore xpub or spscan field population
What changed, and why it matters
This commit is a broad code change that threads a new 'policy type' value through many wallet import paths. The main practical effect visible in the diff is adding support for importing a new kind of Bitcoin wallet called 'silent payments' (policy type SINGLE_SP) from Coldcard hardware wallets. It also makes sure the correct extended public key or silent-payment scan key is set when a keystore is created, depending on the wallet type. There is no explicit mention of a security bug or fix in the commit message or code, but the change touches sensitive key-handling code and removes some workarounds that previously forced wallet-model labels.
Treat this as a feature/refactoring commit with security-sensitive side effects. Review the drongo submodule changes for Keystore factory methods to confirm that xpub/spscan population is correct for all policy types. Verify that removing hard-coded WalletModel values does not cause incorrect source attribution for imported keystores. Test silent-payments import with real Coldcard exports and ensure the SettingsController script-type change does not surprise users or downgrade wallet configurations.
Security signals we found
Adds silent payments (BIP352) scan key import path for Coldcard singlesig
Removes hard-coded WalletModel assignments in several importer subclasses, relying on getWalletModel()
Changes SettingsController script-type selection behavior to always pick the default for the selected policy type
Touches keystore derivation and key population across many import interfaces
No explicit security bug or CVE referenced in commit message or diff
Evidence from the diff
The commit refactors keystore import interfaces and factory methods to accept an explicit PolicyType parameter. This propagates through card, file, mnemonic, xprv, codex and device importers, plus the drongo submodule. The most concrete functional addition is in ColdcardSinglesig: when policyType == SINGLE_SP it parses a ‘bip352’ object containing an ‘spscan’ field and stores it as a SilentPaymentScanAddress, while skipping the normal xpub derivation. Several subclasses (CoboVault, Jade, Keystone, Passport, KeycardShell) stop hard-coding WalletModel values and instead use getWalletModel(). SettingsController now always selects the default script type when the policy type changes, rather than preserving an existing script type if it is still valid. Tests are updated and a new Coldcard silent-payments test fixture is added.
Changed components
src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.javasrc/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.javasrc/main/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesig.javasrc/main/java/com/sparrowwallet/sparrow/io/CoboVaultMultisig.javasrc/main/java/com/sparrowwallet/sparrow/io/KeystoneSinglesig.javasrc/main/java/com/sparrowwallet/sparrow/io/KeystoneMultisig.javasrc/main/java/com/sparrowwallet/sparrow/io/PassportSinglesig.javasrc/main/java/com/sparrowwallet/sparrow/io/PassportMultisig.javasrc/main/java/com/sparrowwallet/sparrow/io/JadeMultisig.javasrc/main/java/com/sparrowwallet/sparrow/io/KeycardShellSinglesig.javasrc/main/java/com/sparrowwallet/sparrow/io/KeycardShellMultisig.javasrc/main/java/com/sparrowwallet/sparrow/io/Bip32.javasrc/main/java/com/sparrowwallet/sparrow/io/Bip39.javasrc/main/java/com/sparrowwallet/sparrow/io/Bip93.javasrc/main/java/com/sparrowwallet/sparrow/io/Slip39.javasrc/main/java/com/sparrowwallet/sparrow/io/Samourai.javasrc/main/java/com/sparrowwallet/sparrow/io/Storage.javasrc/main/java/com/sparrowwallet/sparrow/io/CardApi.java and card implementationssrc/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.javadrongo submoduleInspect captured patch +200 / −108
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java
index 92d7f0d..7cfa4f8 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java
@@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.control;
import com.google.common.base.Throwables;
import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.wallet.*;
@@ -44,6 +45,7 @@ public class CardImportPane extends TitledDescriptionPane {
private static final Logger log = LoggerFactory.getLogger(CardImportPane.class);
private final KeystoreCardImport importer;
+ private final PolicyType policyType;
private List<ChildNumber> derivation;
protected Button importButton;
private final SimpleStringProperty pin = new SimpleStringProperty("");
@@ -51,6 +53,7 @@ public class CardImportPane extends TitledDescriptionPane {
public CardImportPane(Wallet wallet, KeystoreCardImport importer, KeyDerivation defaultDerivation, KeyDerivation requiredDerivation) {
super(importer.getName(), "Place card on reader", importer.getKeystoreImportDescription(getAccount(wallet, requiredDerivation)), importer.getWalletModel());
this.importer = importer;
+ this.policyType = wallet.getPolicyType();
this.derivation = requiredDerivation == null ? getDefaultDerivation(wallet, defaultDerivation) : requiredDerivation.getDerivation();
}
@@ -59,7 +62,7 @@ public class CardImportPane extends TitledDescriptionPane {
return defaultDerivation.getDerivation();
}
- return wallet == null || wallet.getScriptType() == null ? ScriptType.P2WPKH.getDefaultDerivation() : wallet.getScriptType().getDefaultDerivation();
+ return wallet.getScriptType() == null ? ScriptType.P2WPKH.getDefaultDerivation() : wallet.getScriptType().getDefaultDerivation();
}
@Override
@@ -111,7 +114,7 @@ public class CardImportPane extends TitledDescriptionPane {
return;
}
- CardImportService cardImportService = new CardImportService(importer, pin.get(), derivation, messageProperty);
+ CardImportService cardImportService = new CardImportService(importer, policyType, pin.get(), derivation, messageProperty);
cardImportService.setOnSucceeded(event -> {
EventManager.get().post(new KeystoreImportEvent(cardImportService.getValue()));
});
@@ -352,12 +355,14 @@ public class CardImportPane extends TitledDescriptionPane {
public static class CardImportService extends Service<Keystore> {
private final KeystoreCardImport cardImport;
+ private final PolicyType policyType;
private final String pin;
private final List<ChildNumber> derivation;
private final StringProperty messageProperty;
- public CardImportService(KeystoreCardImport cardImport, String pin, List<ChildNumber> derivation, StringProperty messageProperty) {
+ public CardImportService(KeystoreCardImport cardImport, PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) {
this.cardImport = cardImport;
+ this.policyType = policyType;
this.pin = pin;
this.derivation = derivation;
this.messageProperty = messageProperty;
@@ -368,7 +373,7 @@ public class CardImportPane extends TitledDescriptionPane {
return new Task<>() {
@Override
protected Keystore call() throws Exception {
- return cardImport.getKeystore(pin, derivation, messageProperty);
+ return cardImport.getKeystore(policyType, pin, derivation, messageProperty);
}
};
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/CodexKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/CodexKeystoreImportPane.java
index deaf96c..f49d48e 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/CodexKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/CodexKeystoreImportPane.java
@@ -81,7 +81,7 @@ public class CodexKeystoreImportPane extends TitledDescriptionPane {
private void importKeystore(List<ChildNumber> derivation) {
importButton.setDisable(true);
try {
- Keystore keystore = importer.getKeystore(derivation, secretShareProperty.get());
+ Keystore keystore = importer.getKeystore(wallet.getPolicyType(), derivation, secretShareProperty.get());
EventManager.get().post(new KeystoreImportEvent(keystore));
} catch(ImportException e) {
String errorMessage = e.getMessage();
@@ -125,7 +125,7 @@ public class CodexKeystoreImportPane extends TitledDescriptionPane {
private void onInputChange(boolean empty, boolean validChecksum) {
if(!empty) {
try {
- importer.getKeystore(ScriptType.P2WPKH.getDefaultDerivation(), secretShareProperty.get());
+ importer.getKeystore(wallet.getPolicyType(), ScriptType.P2WPKH.getDefaultDerivation(), secretShareProperty.get());
validChecksum = true;
} catch(ImportException e) {
invalidLabel.setText("Invalid checksum");
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java
index 06ca959..29a6926 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java
@@ -711,7 +711,7 @@ public class DevicePane extends TitledDescriptionPane {
return;
}
- Service<Keystore> importService = cardApi.getImportService(derivation, messageProperty);
+ Service<Keystore> importService = cardApi.getImportService(wallet.getPolicyType(), derivation, messageProperty);
handleCardOperation(importService, importButton, "Import", true, event -> {
importKeystore(derivation, importService.getValue());
});
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java
index bb1a4d4..714a714 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/FileKeystoreImportPane.java
@@ -25,7 +25,7 @@ public class FileKeystoreImportPane extends FileImportPane {
protected void importFile(String fileName, InputStream inputStream, String password) throws ImportException {
Keystore keystore = getScannedKeystore(wallet.getScriptType());
if(keystore == null) {
- keystore = importer.getKeystore(wallet.getScriptType(), inputStream, password);
+ keystore = importer.getKeystore(wallet.getPolicyType(), wallet.getScriptType(), inputStream, password);
}
if(requiredDerivation != null && !requiredDerivation.getDerivation().equals(keystore.getKeyDerivation().getDerivation())) {
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java
index ca0be68..f873229 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java
@@ -86,7 +86,7 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
EventManager.get().post(new WalletImportEvent(wallet));
} else {
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
- Keystore keystore = importer.getKeystore(scriptType, bais, password);
+ Keystore keystore = importer.getKeystore(PolicyType.SINGLE_HD, scriptType, bais, password);
Wallet wallet = new Wallet();
wallet.setName(Files.getNameWithoutExtension(fileName));
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreImportPane.java
index 8ef0854..70a28b7 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreImportPane.java
@@ -141,7 +141,7 @@ public class MnemonicKeystoreImportPane extends MnemonicKeystorePane {
protected void onWordChange(boolean empty, boolean validWords, boolean validChecksum) {
if(!empty && validWords) {
try {
- importer.getKeystore(wallet.getScriptType().getDefaultDerivation(), wordEntriesProperty.get(), passphraseProperty.get());
+ importer.getKeystore(wallet.getPolicyType(), wallet.getScriptType().getDefaultDerivation(), wordEntriesProperty.get(), passphraseProperty.get());
validChecksum = true;
} catch(ImportException e) {
if(e.getCause() instanceof MnemonicException.MnemonicTypeException) {
@@ -256,7 +256,7 @@ public class MnemonicKeystoreImportPane extends MnemonicKeystorePane {
private boolean importKeystore(List<ChildNumber> derivation, boolean dryrun) {
importButton.setDisable(true);
try {
- Keystore keystore = importer.getKeystore(derivation, wordEntriesProperty.get(), passphraseProperty.get());
+ Keystore keystore = importer.getKeystore(wallet.getPolicyType(), derivation, wordEntriesProperty.get(), passphraseProperty.get());
if(!dryrun) {
if(passphraseProperty.get() != null && !passphraseProperty.get().isEmpty()) {
KeystorePassphraseDialog keystorePassphraseDialog = new KeystorePassphraseDialog(null, keystore, true);
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicShareKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicShareKeystoreImportPane.java
index a3885f1..bda3ff2 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicShareKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicShareKeystoreImportPane.java
@@ -162,7 +162,7 @@ public class MnemonicShareKeystoreImportPane extends MnemonicKeystorePane {
existing.add(wordEntriesProperty.get());
}
- importer.getKeystore(wallet.getScriptType().getDefaultDerivation(), existing, passphraseProperty.get());
+ importer.getKeystore(wallet.getPolicyType(), wallet.getScriptType().getDefaultDerivation(), existing, passphraseProperty.get());
validSet = true;
complete = true;
} catch(MnemonicException e) {
@@ -240,7 +240,7 @@ public class MnemonicShareKeystoreImportPane extends MnemonicKeystorePane {
private boolean importKeystore(List<ChildNumber> derivation, boolean dryrun) {
importButton.setDisable(true);
try {
- Keystore keystore = importer.getKeystore(derivation, mnemonicShares, passphraseProperty.get());
+ Keystore keystore = importer.getKeystore(wallet.getPolicyType(), derivation, mnemonicShares, passphraseProperty.get());
if(!dryrun) {
if(passphraseProperty.get() != null && !passphraseProperty.get().isEmpty()) {
KeystorePassphraseDialog keystorePassphraseDialog = new KeystorePassphraseDialog(null, keystore, true);
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicWalletKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicWalletKeystoreImportPane.java
index b361eaf..bdb8cf7 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicWalletKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicWalletKeystoreImportPane.java
@@ -81,7 +81,7 @@ public class MnemonicWalletKeystoreImportPane extends MnemonicKeystorePane {
protected void onWordChange(boolean empty, boolean validWords, boolean validChecksum) {
if(!empty && validWords) {
try {
- importer.getKeystore(ScriptType.P2WPKH.getDefaultDerivation(), wordEntriesProperty.get(), passphraseProperty.get());
+ importer.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH.getDefaultDerivation(), wordEntriesProperty.get(), passphraseProperty.get());
validChecksum = true;
} catch(ImportException e) {
if(e.getCause() instanceof MnemonicException.MnemonicTypeException) {
@@ -167,7 +167,7 @@ public class MnemonicWalletKeystoreImportPane extends MnemonicKeystorePane {
Wallet wallet = new Wallet("");
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType);
- Keystore keystore = importer.getKeystore(derivation, wordEntriesProperty.get(), passphraseProperty.get());
+ Keystore keystore = importer.getKeystore(PolicyType.SINGLE_HD, derivation, wordEntriesProperty.get(), passphraseProperty.get());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, scriptType, wallet.getKeystores(), 1));
return wallet;
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/XprvKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/XprvKeystoreImportPane.java
index 06a16eb..835bb4d 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/XprvKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/XprvKeystoreImportPane.java
@@ -114,7 +114,7 @@ public class XprvKeystoreImportPane extends TitledDescriptionPane {
private void importKeystore(List<ChildNumber> derivation) {
importButton.setDisable(true);
try {
- Keystore keystore = importer.getKeystore(derivation, xprv);
+ Keystore keystore = importer.getKeystore(wallet.getPolicyType(), derivation, xprv);
EventManager.get().post(new KeystoreImportEvent(keystore));
} catch (ImportException e) {
String errorMessage = e.getMessage();
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Bip129.java b/src/main/java/com/sparrowwallet/sparrow/io/Bip129.java
index cae0bce..5083a1a 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Bip129.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Bip129.java
@@ -4,6 +4,7 @@ import com.google.common.io.CharStreams;
import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.OutputDescriptor;
import com.sparrowwallet.drongo.Utils;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.crypto.Pbkdf2KeyDeriver;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
@@ -93,7 +94,7 @@ public class Bip129 implements KeystoreFileExport, KeystoreFileImport, WalletExp
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
if(password != null) {
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Bip32.java b/src/main/java/com/sparrowwallet/sparrow/io/Bip32.java
index f144c50..1c660b0 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Bip32.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Bip32.java
@@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.MasterPrivateExtendedKey;
import com.sparrowwallet.drongo.wallet.WalletModel;
@@ -25,10 +26,10 @@ public class Bip32 implements KeystoreXprvImport {
}
@Override
- public Keystore getKeystore(List<ChildNumber> derivation, ExtendedKey xprv) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, ExtendedKey xprv) throws ImportException {
try {
MasterPrivateExtendedKey masterPrivateExtendedKey = new MasterPrivateExtendedKey(xprv.getKey().getPrivKeyBytes(), xprv.getKey().getChainCode());
- return Keystore.fromMasterPrivateExtendedKey(masterPrivateExtendedKey, derivation);
+ return Keystore.fromMasterPrivateExtendedKey(masterPrivateExtendedKey, policyType, derivation);
} catch(Exception e) {
throw new ImportException(e);
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java b/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java
index 9b679b4..a837984 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Bip39.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.*;
import java.util.List;
@@ -22,11 +23,11 @@ public class Bip39 implements KeystoreMnemonicImport {
}
@Override
- public Keystore getKeystore(List<ChildNumber> derivation, List<String> mnemonicWords, String passphrase) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, List<String> mnemonicWords, String passphrase) throws ImportException {
try {
Bip39MnemonicCode.INSTANCE.check(mnemonicWords);
DeterministicSeed seed = new DeterministicSeed(mnemonicWords, passphrase, System.currentTimeMillis(), DeterministicSeed.Type.BIP39);
- return Keystore.fromSeed(seed, derivation);
+ return Keystore.fromSeed(seed, policyType, derivation);
} catch (Exception e) {
try {
ElectrumMnemonicCode.INSTANCE.check(mnemonicWords);
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Bip93.java b/src/main/java/com/sparrowwallet/sparrow/io/Bip93.java
index 1502ae6..64a5b54 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Bip93.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Bip93.java
@@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.crypto.ChildNumber;
import com.sparrowwallet.drongo.crypto.DeterministicKey;
import com.sparrowwallet.drongo.crypto.HDKeyDerivation;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.MasterPrivateExtendedKey;
import com.sparrowwallet.drongo.wallet.MnemonicException;
@@ -28,12 +29,12 @@ public class Bip93 implements KeystoreCodexImport {
}
@Override
- public Keystore getKeystore(List<ChildNumber> derivation, String secretShare) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, String secretShare) throws ImportException {
try {
Codex32.Codex32Data secretData = Codex32.decode(secretShare);
DeterministicKey key = HDKeyDerivation.createMasterPrivateKey(secretData.payloadToBip32Secret());
MasterPrivateExtendedKey mpek = new MasterPrivateExtendedKey(key);
- Keystore keystore = Keystore.fromMasterPrivateExtendedKey(mpek, derivation);
+ Keystore keystore = Keystore.fromMasterPrivateExtendedKey(mpek, policyType, derivation);
keystore.setLabel("BIP93");
return keystore;
} catch(MnemonicException e) {
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java
index e010143..c1b4531 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java
@@ -5,6 +5,7 @@ import com.sparrowwallet.drongo.OsType;
import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.crypto.ChildNumber;
import com.sparrowwallet.drongo.crypto.ECKey;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.Keystore;
@@ -107,7 +108,7 @@ public abstract class CardApi {
public abstract Service<Void> getInitializationService(byte[] entropy, StringProperty messageProperty);
- public abstract Service<Keystore> getImportService(List<ChildNumber> derivation, StringProperty messageProperty);
+ public abstract Service<Keystore> getImportService(PolicyType policyType, List<ChildNumber> derivation, StringProperty messageProperty);
public abstract Service<PSBT> getSignService(Wallet wallet, PSBT psbt, StringProperty messageProperty);
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultMultisig.java
index 4c12168..28dd813 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultMultisig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultMultisig.java
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
@@ -19,10 +20,9 @@ public class CoboVaultMultisig extends ColdcardMultisig {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
- Keystore keystore = super.getKeystore(scriptType, inputStream, password);
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ Keystore keystore = super.getKeystore(policyType, scriptType, inputStream, password);
keystore.setLabel("Cobo Vault");
- keystore.setWalletModel(getWalletModel());
return keystore;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesig.java b/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesig.java
index bc50c8e..ad1ea3f 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesig.java
@@ -35,7 +35,7 @@ public class CoboVaultSinglesig implements KeystoreFileImport, WalletImport {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
try {
Gson gson = new Gson();
CoboVaultSinglesigKeystore coboKeystore = gson.fromJson(new InputStreamReader(inputStream, StandardCharsets.UTF_8), CoboVaultSinglesigKeystore.class);
@@ -47,7 +47,7 @@ public class CoboVaultSinglesig implements KeystoreFileImport, WalletImport {
Keystore keystore = new Keystore();
keystore.setLabel(getName());
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
- keystore.setWalletModel(WalletModel.COBO_VAULT);
+ keystore.setWalletModel(getWalletModel());
keystore.setKeyDerivation(new KeyDerivation(coboKeystore.MasterFingerprint.toLowerCase(Locale.ROOT), "m/" + coboKeystore.AccountKeyPath, true));
keystore.setExtendedPublicKey(ExtendedKey.fromDescriptor(coboKeystore.ExtPubKey));
@@ -70,7 +70,7 @@ public class CoboVaultSinglesig implements KeystoreFileImport, WalletImport {
@Override
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
//Use default of P2WPKH
- Keystore keystore = getKeystore(ScriptType.P2WPKH, inputStream, "");
+ Keystore keystore = getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH, inputStream, "");
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE_HD);
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java
index 91660c5..945f02d 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java
@@ -32,7 +32,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
inputStream.transferTo(baos);
@@ -41,9 +41,9 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
Keystore keystore;
try {
- keystore = getKeystoreMultisig(scriptType, firstClone, password);
+ keystore = getKeystoreMultisig(policyType, scriptType, firstClone, password);
} catch(Exception e) {
- keystore = getKeystoreSinglesig(scriptType, secondClone, password);
+ keystore = getKeystoreSinglesig(policyType, scriptType, secondClone, password);
}
return keystore;
@@ -52,18 +52,18 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
}
}
- private Keystore getKeystoreSinglesig(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ private Keystore getKeystoreSinglesig(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
ColdcardSinglesig coldcardSinglesig = new ColdcardSinglesig();
- return coldcardSinglesig.getKeystore(scriptType, inputStream, password);
+ return coldcardSinglesig.getKeystore(policyType, scriptType, inputStream, password);
}
- public Keystore getKeystoreMultisig(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystoreMultisig(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
ColdcardKeystore cck = JsonPersistence.getGson().fromJson(reader, ColdcardKeystore.class);
Keystore keystore = new Keystore("Coldcard");
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
- keystore.setWalletModel(WalletModel.COLDCARD);
+ keystore.setWalletModel(getWalletModel());
try {
if(cck.xpub != null && cck.path != null) {
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java
index df80e8c..af63973 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardSinglesig.java
@@ -8,6 +8,7 @@ import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.policy.Policy;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
+import com.sparrowwallet.drongo.silentpayments.SilentPaymentScanAddress;
import com.sparrowwallet.drongo.wallet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,7 +55,7 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
try {
Gson gson = new Gson();
Type stringStringMap = new TypeToken<Map<String, JsonElement>>() {
@@ -67,6 +68,22 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
String masterFingerprint = map.get("xfp").getAsString();
+ if(policyType == PolicyType.SINGLE_SP) {
+ JsonElement bip352Element = map.get("bip352");
+ if(bip352Element == null) {
+ throw new ImportException("File does not contain an export for silent payments");
+ }
+
+ ColdcardKeystore ck = gson.fromJson(bip352Element, ColdcardKeystore.class);
+ Keystore keystore = new Keystore();
+ keystore.setLabel(getName());
+ keystore.setSource(KeystoreSource.HW_AIRGAPPED);
+ keystore.setWalletModel(getWalletModel());
+ keystore.setKeyDerivation(new KeyDerivation(masterFingerprint, ck.deriv, true));
+ keystore.setSilentPaymentScanAddress(SilentPaymentScanAddress.fromKeyString(ck.spscan));
+ return keystore;
+ }
+
for (String key : map.keySet()) {
if (key.startsWith("bip")) {
ColdcardKeystore ck = gson.fromJson(map.get(key), ColdcardKeystore.class);
@@ -77,7 +94,7 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
Keystore keystore = new Keystore();
keystore.setLabel(getName());
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
- keystore.setWalletModel(WalletModel.COLDCARD);
+ keystore.setWalletModel(getWalletModel());
keystore.setKeyDerivation(new KeyDerivation(masterFingerprint, ck.deriv, true));
keystore.setExtendedPublicKey(ExtendedKey.fromDescriptor(ck.xpub));
@@ -101,7 +118,7 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
@Override
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
//Use default of P2WPKH
- Keystore keystore = getKeystore(ScriptType.P2WPKH, inputStream, "");
+ Keystore keystore = getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH, inputStream, "");
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE_HD);
@@ -122,6 +139,7 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
public String deriv;
public String name;
public String xpub;
+ public String spscan;
public String xfp;
}
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java b/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java
index 4e78ad7..ab7cc63 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Electrum.java
@@ -40,10 +40,10 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
Wallet wallet = importWallet(inputStream, password);
- if(!wallet.getPolicyType().equals(PolicyType.SINGLE_HD) || wallet.getKeystores().size() != 1) {
+ if(wallet.getPolicyType().equals(PolicyType.MULTI_HD) || wallet.getKeystores().size() != 1) {
throw new ImportException("Multisig wallet detected - import it using File > Import Wallet");
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java b/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java
index 9f03bd5..b2660a4 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/GordianSeedTool.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.Network;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
@@ -25,7 +26,7 @@ public class GordianSeedTool implements KeystoreFileImport {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
throw new ImportException("Only QR imports are supported.");
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Jade.java b/src/main/java/com/sparrowwallet/sparrow/io/Jade.java
index 2f21d15..0905f11 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Jade.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Jade.java
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
@@ -24,7 +25,7 @@ public class Jade implements KeystoreFileImport {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
throw new ImportException("Failed to detect a valid " + scriptType.getDescription() + " keystore.");
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/JadeMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/JadeMultisig.java
index 9d5897c..0566532 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/JadeMultisig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/JadeMultisig.java
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
@@ -63,14 +64,13 @@ public class JadeMultisig extends ColdcardMultisig {
Wallet wallet = super.importWallet(inputStream, password);
for(Keystore keystore : wallet.getKeystores()) {
keystore.setLabel(keystore.getLabel().replace("Coldcard", "Jade"));
- keystore.setWalletModel(WalletModel.JADE);
}
return wallet;
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
throw new ImportException("Failed to detect a valid " + scriptType.getDescription() + " keystore.");
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellMultisig.java
index 98dd093..f689490 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellMultisig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellMultisig.java
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
@@ -23,10 +24,9 @@ public class KeycardShellMultisig extends ColdcardMultisig {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
- Keystore keystore = super.getKeystore(scriptType, inputStream, password);
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ Keystore keystore = super.getKeystore(policyType, scriptType, inputStream, password);
keystore.setLabel("Keycard Shell");
- keystore.setWalletModel(getWalletModel());
return keystore;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellSinglesig.java b/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellSinglesig.java
index dc65b59..d2a32f2 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellSinglesig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeycardShellSinglesig.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.Network;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
@@ -24,10 +25,9 @@ public class KeycardShellSinglesig extends KeystoneSinglesig {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
- Keystore keystore = super.getKeystore(scriptType, inputStream, password);
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ Keystore keystore = super.getKeystore(policyType, scriptType, inputStream, password);
keystore.setLabel("Keycard Shell");
- keystore.setWalletModel(getWalletModel());
return keystore;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoneMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoneMultisig.java
index e300495..ab19dbf 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoneMultisig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoneMultisig.java
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
@@ -19,10 +20,9 @@ public class KeystoneMultisig extends ColdcardMultisig {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
- Keystore keystore = super.getKeystore(scriptType, inputStream, password);
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ Keystore keystore = super.getKeystore(policyType, scriptType, inputStream, password);
keystore.setLabel("Keystone");
- keystore.setWalletModel(getWalletModel());
return keystore;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoneSinglesig.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoneSinglesig.java
index b8d518c..c47e8be 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoneSinglesig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoneSinglesig.java
@@ -36,7 +36,7 @@ public class KeystoneSinglesig implements KeystoreFileImport, WalletImport {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
try {
String outputDescriptor = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("\n"));
OutputDescriptor descriptor = OutputDescriptor.getOutputDescriptor(outputDescriptor);
@@ -55,7 +55,7 @@ public class KeystoneSinglesig implements KeystoreFileImport, WalletImport {
Keystore keystore = new Keystore();
keystore.setLabel(getName());
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
- keystore.setWalletModel(WalletModel.KEYSTONE);
+ keystore.setWalletModel(getWalletModel());
keystore.setKeyDerivation(keyDerivation);
keystore.setExtendedPublicKey(xpub);
@@ -75,7 +75,7 @@ public class KeystoneSinglesig implements KeystoreFileImport, WalletImport {
@Override
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
//Use default of P2WPKH
- Keystore keystore = getKeystore(ScriptType.P2WPKH, inputStream, "");
+ Keystore keystore = getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH, inputStream, "");
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE_HD);
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java
index 090e19d..9e2260e 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java
@@ -1,12 +1,13 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import javafx.beans.property.StringProperty;
import java.util.List;
public interface KeystoreCardImport extends CardImport {
- Keystore getKeystore(String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException;
+ Keystore getKeystore(PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException;
String getKeystoreImportDescription(int account);
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCodexImport.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCodexImport.java
index a02c2ec..553448d 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCodexImport.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCodexImport.java
@@ -1,10 +1,11 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import java.util.List;
public interface KeystoreCodexImport extends KeystoreImport {
- Keystore getKeystore(List<ChildNumber> derivation, String secretShare) throws ImportException;
+ Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, String secretShare) throws ImportException;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreFileImport.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreFileImport.java
index ce1dddd..19cdb72 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreFileImport.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreFileImport.java
@@ -1,12 +1,13 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import java.io.InputStream;
public interface KeystoreFileImport extends KeystoreImport, FileImport {
- Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException;
+ Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException;
String getKeystoreImportDescription(int account);
default String getKeystoreImportDescription() {
return getKeystoreImportDescription(0);
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicImport.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicImport.java
index d12aaaf..bbcdca7 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicImport.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicImport.java
@@ -1,10 +1,11 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import java.util.List;
public interface KeystoreMnemonicImport extends KeystoreImport {
- Keystore getKeystore(List<ChildNumber> derivation, List<String> mnemonicWords, String passphrase) throws ImportException;
+ Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, List<String> mnemonicWords, String passphrase) throws ImportException;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicShareImport.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicShareImport.java
index 3b3866e..41671e7 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicShareImport.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreMnemonicShareImport.java
@@ -1,10 +1,11 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import java.util.List;
public interface KeystoreMnemonicShareImport extends KeystoreImport {
- Keystore getKeystore(List<ChildNumber> derivation, List<List<String>> mnemonicShares, String passphrase) throws ImportException;
+ Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, List<List<String>> mnemonicShares, String passphrase) throws ImportException;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreXprvImport.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreXprvImport.java
index eb6006f..41a2095 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreXprvImport.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreXprvImport.java
@@ -2,10 +2,11 @@ package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import java.util.List;
public interface KeystoreXprvImport extends KeystoreImport {
- Keystore getKeystore(List<ChildNumber> derivation, ExtendedKey xprv) throws ImportException;
+ Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, ExtendedKey xprv) throws ImportException;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/PassportMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/PassportMultisig.java
index 87d99af..73cf21c 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/PassportMultisig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/PassportMultisig.java
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
@@ -19,10 +20,9 @@ public class PassportMultisig extends ColdcardMultisig {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
- Keystore keystore = super.getKeystore(scriptType, inputStream, password);
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ Keystore keystore = super.getKeystore(policyType, scriptType, inputStream, password);
keystore.setLabel("Passport");
- keystore.setWalletModel(getWalletModel());
return keystore;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/PassportSinglesig.java b/src/main/java/com/sparrowwallet/sparrow/io/PassportSinglesig.java
index ab4887c..477e95e 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/PassportSinglesig.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/PassportSinglesig.java
@@ -1,5 +1,6 @@
package com.sparrowwallet.sparrow.io;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
@@ -18,10 +19,9 @@ public class PassportSinglesig extends ColdcardSinglesig {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
- Keystore keystore = super.getKeystore(scriptType, inputStream, password);
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ Keystore keystore = super.getKeystore(policyType, scriptType, inputStream, password);
keystore.setLabel("Passport");
- keystore.setWalletModel(getWalletModel());
return keystore;
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Samourai.java b/src/main/java/com/sparrowwallet/sparrow/io/Samourai.java
index 0ed872a..6b7e2a9 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Samourai.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Samourai.java
@@ -7,6 +7,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.SamouraiUtil;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.*;
@@ -25,7 +26,7 @@ public class Samourai implements KeystoreFileImport {
}
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
try {
String input = CharStreams.toString(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
@@ -52,7 +53,7 @@ public class Samourai implements KeystoreFileImport {
SamouraiBackup backup = new Gson().fromJson(decrypted, SamouraiBackup.class);
DeterministicSeed seed = new DeterministicSeed(Utils.hexToBytes(backup.wallet.seed), password, 0);
- Keystore keystore = Keystore.fromSeed(seed, scriptType.getDefaultDerivation());
+ Keystore keystore = Keystore.fromSeed(seed, PolicyType.SINGLE_HD, scriptType.getDefaultDerivation());
keystore.setLabel(getWalletModel().toDisplayString());
return keystore;
} catch(JsonParseException e) {
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Slip39.java b/src/main/java/com/sparrowwallet/sparrow/io/Slip39.java
index e0afd31..32fe8da 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Slip39.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Slip39.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.drongo.wallet.slip39.RecoveryState;
import com.sparrowwallet.drongo.wallet.slip39.Share;
@@ -25,7 +26,7 @@ public class Slip39 implements KeystoreMnemonicShareImport {
}
@Override
- public Keystore getKeystore(List<ChildNumber> derivation, List<List<String>> mnemonicShares, String passphrase) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, List<ChildNumber> derivation, List<List<String>> mnemonicShares, String passphrase) throws ImportException {
try {
RecoveryState recoveryState = new RecoveryState();
for(List<String> mnemonicWords : mnemonicShares) {
@@ -36,7 +37,7 @@ public class Slip39 implements KeystoreMnemonicShareImport {
if(recoveryState.isComplete()) {
byte[] secret = recoveryState.recover(passphrase.getBytes(StandardCharsets.UTF_8));
DeterministicSeed seed = new DeterministicSeed(secret, passphrase, System.currentTimeMillis(), DeterministicSeed.Type.SLIP39);
- return Keystore.fromSeed(seed, derivation);
+ return Keystore.fromSeed(seed, policyType, derivation);
} else {
throw new Slip39ProgressException(recoveryState.getShortStatus(), recoveryState.getStatus());
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java b/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java
index 782513d..ead4e5d 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java
@@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.io;
import com.google.common.io.CharStreams;
import com.sparrowwallet.drongo.OutputDescriptor;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
@@ -17,7 +18,7 @@ public class SpecterDIY implements KeystoreFileImport, WalletExport {
private static final Logger log = LoggerFactory.getLogger(SpecterDIY.class);
@Override
- public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
try {
String text = CharStreams.toString(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String outputDesc = "sh(" + text + ")";
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java
index f461754..1945b08 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java
@@ -183,7 +183,7 @@ public class Storage {
Keystore keystore = wallet.getKeystores().get(i);
if(keystore.hasSeed()) {
Keystore copyKeystore = copy.getKeystores().get(i);
- Keystore derivedKeystore = Keystore.fromSeed(copyKeystore.getSeed(), copyKeystore.getKeyDerivation().getDerivation());
+ Keystore derivedKeystore = Keystore.fromSeed(copyKeystore.getSeed(), wallet.getPolicyType(), copyKeystore.getKeyDerivation().getDerivation());
keystore.setKeyDerivation(derivedKeystore.getKeyDerivation());
keystore.setExtendedPublicKey(derivedKeystore.getExtendedPublicKey());
keystore.getSeed().setPassphrase(copyKeystore.getSeed().getPassphrase());
@@ -192,7 +192,7 @@ public class Storage {
copyKeystore.getSeed().clear();
} else if(keystore.hasMasterPrivateExtendedKey()) {
Keystore copyKeystore = copy.getKeystores().get(i);
- Keystore derivedKeystore = Keystore.fromMasterPrivateExtendedKey(copyKeystore.getMasterPrivateExtendedKey(), copyKeystore.getKeyDerivation().getDerivation());
+ Keystore derivedKeystore = Keystore.fromMasterPrivateExtendedKey(copyKeystore.getMasterPrivateExtendedKey(), wallet.getPolicyType(), copyKeystore.getKeyDerivation().getDerivation());
keystore.setKeyDerivation(derivedKeystore.getKeyDerivation());
keystore.setExtendedPublicKey(derivedKeystore.getExtendedPublicKey());
keystore.setBip47ExtendedPrivateKey(derivedKeystore.getBip47ExtendedPrivateKey());
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java
index 909c244..1e4e347 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java
@@ -142,12 +142,12 @@ public class CkCardApi extends CardApi {
}
@Override
- public Service<Keystore> getImportService(List<ChildNumber> derivation, StringProperty messageProperty) {
+ public Service<Keystore> getImportService(PolicyType policyType, List<ChildNumber> derivation, StringProperty messageProperty) {
if(cardType == WalletModel.SATSCHIP) {
- return new CardImportPane.CardImportService(new Satschip(), cvc, derivation, messageProperty);
+ return new CardImportPane.CardImportService(new Satschip(), policyType, cvc, derivation, messageProperty);
}
- return new CardImportPane.CardImportService(new Tapsigner(), cvc, derivation, messageProperty);
+ return new CardImportPane.CardImportService(new Tapsigner(), policyType, cvc, derivation, messageProperty);
}
@Override
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/Tapsigner.java b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/Tapsigner.java
index b85c0a8..12ab589 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/Tapsigner.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/Tapsigner.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io.ckcard;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
import com.sparrowwallet.sparrow.io.KeystoreCardImport;
@@ -52,7 +53,7 @@ public class Tapsigner implements KeystoreCardImport {
}
@Override
- public Keystore getKeystore(String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
if(pin.length() < 6) {
throw new ImportException("PIN too short.");
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/keycard/Keycard.java b/src/main/java/com/sparrowwallet/sparrow/io/keycard/Keycard.java
index 1ca147d..dd9924b 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/keycard/Keycard.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/keycard/Keycard.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io.keycard;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
import com.sparrowwallet.sparrow.io.ImportException;
@@ -52,7 +53,7 @@ public class Keycard implements KeystoreCardImport {
}
@Override
- public Keystore getKeystore(String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
if(!StringUtils.isNumeric(pin)) {
throw new ImportException("PIN must be all digits.");
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/keycard/KeycardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/keycard/KeycardApi.java
index c591223..59c7be4 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/keycard/KeycardApi.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/keycard/KeycardApi.java
@@ -5,6 +5,7 @@ import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.crypto.ChildNumber;
import com.sparrowwallet.drongo.crypto.ECDSASignature;
import com.sparrowwallet.drongo.crypto.ECKey;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
@@ -145,8 +146,8 @@ public class KeycardApi extends CardApi {
}
@Override
- public Service<Keystore> getImportService(List<ChildNumber> derivation, StringProperty messageProperty) {
- return new CardImportPane.CardImportService(new Keycard(), pin, derivation, messageProperty);
+ public Service<Keystore> getImportService(PolicyType policyType, List<ChildNumber> derivation, StringProperty messageProperty) {
+ return new CardImportPane.CardImportService(new Keycard(), policyType, pin, derivation, messageProperty);
}
private byte[] compressedPub(byte[] uncompressedPub) {
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/satochip/SatoCardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/satochip/SatoCardApi.java
index c37a5bb..2d28991 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/satochip/SatoCardApi.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/satochip/SatoCardApi.java
@@ -9,6 +9,7 @@ import com.sparrowwallet.drongo.crypto.ChildNumber;
import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.crypto.ECDSASignature;
import com.sparrowwallet.drongo.crypto.SchnorrSignature;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
@@ -122,8 +123,8 @@ public class SatoCardApi extends CardApi {
}
@Override
- public Service<Keystore> getImportService(List<ChildNumber> derivation, StringProperty messageProperty) {
- return new CardImportPane.CardImportService(new Satochip(), pin, derivation, messageProperty);
+ public Service<Keystore> getImportService(PolicyType policyType, List<ChildNumber> derivation, StringProperty messageProperty) {
+ return new CardImportPane.CardImportService(new Satochip(), policyType, pin, derivation, messageProperty);
}
/*
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/satochip/Satochip.java b/src/main/java/com/sparrowwallet/sparrow/io/satochip/Satochip.java
index 8c16150..29aa6b0 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/satochip/Satochip.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/satochip/Satochip.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io.satochip;
import com.sparrowwallet.drongo.crypto.ChildNumber;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.WalletModel;
import com.sparrowwallet.sparrow.io.KeystoreCardImport;
@@ -51,7 +52,7 @@ public class Satochip implements KeystoreCardImport {
}
@Override
- public Keystore getKeystore(String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
+ public Keystore getKeystore(PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
if(pin.length() < 4) {
throw new ImportException("PIN too short.");
}
diff --git a/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java b/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java
index 114c6fb..39cdeb9 100644
--- a/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java
+++ b/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java
@@ -30,6 +30,8 @@ public class HwAirgappedController extends KeystoreImportDetailController {
fileImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new Jade(), new KeystoneSinglesig(), new PassportSinglesig(), new SeedSigner(), new GordianSeedTool(), new SpecterDIY(), new Krux(), new AirGapVault(), new KeycardShellSinglesig());
} else if(getMasterController().getWallet().getPolicyType().equals(PolicyType.MULTI_HD)) {
fileImporters = List.of(new Bip129(), new ColdcardMultisig(), new CoboVaultMultisig(), new JadeMultisig(), new KeystoneMultisig(), new PassportMultisig(), new SeedSigner(), new GordianSeedTool(), new SpecterDIY(), new Krux(), new KeycardShellMultisig());
+ } else if(getMasterController().getWallet().getPolicyType().equals(PolicyType.SINGLE_SP)) {
+ fileImporters = List.of(new ColdcardSinglesig());
}
for(KeystoreFileImport importer : fileImporters) {
diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/Bip39Dialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/Bip39Dialog.java
index 1b5b9b1..a1826c5 100644
--- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/Bip39Dialog.java
+++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/Bip39Dialog.java
@@ -74,7 +74,7 @@ public class Bip39Dialog extends NewWalletDialog {
seedWords.setTextChangeListener((newText, changedByUserInteraction) -> {
try {
String[] words = newText.split("[ \n]");
- importer.getKeystore(scriptType.getSelectedItem().scriptType.getDefaultDerivation(), Arrays.asList(words), passphrase.getText());
+ importer.getKeystore(PolicyType.SINGLE_HD, scriptType.getSelectedItem().scriptType.getDefaultDerivation(), Arrays.asList(words), passphrase.getText());
createWallet.setEnabled(true);
} catch(ImportException e) {
createWallet.setEnabled(false);
@@ -152,7 +152,7 @@ public class Bip39Dialog extends NewWalletDialog {
Wallet wallet = new Wallet(walletName);
wallet.setPolicyType(PolicyType.SINGLE_HD);
wallet.setScriptType(scriptType.getSelectedItem().scriptType);
- Keystore keystore = importer.getKeystore(wallet.getScriptType().getDefaultDerivation(), getWords(), passphrase.getText());
+ Keystore keystore = importer.getKeystore(PolicyType.SINGLE_HD, wallet.getScriptType().getDefaultDerivation(), getWords(), passphrase.getText());
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE_HD, wallet.getScriptType(), wallet.getKeystores(), 1));
return List.of(wallet);
diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java
index e695d05..e1c2fe7 100644
--- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java
+++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java
@@ -1034,7 +1034,7 @@ public class HeadersController extends TransactionFormController implements Init
private void signFromSeed(DeterministicSeed seed) {
try {
- String masterFingerprint = Keystore.fromSeed(seed, ScriptType.P2PKH.getDefaultDerivation()).getKeyDerivation().getMasterFingerprint();
+ String masterFingerprint = Keystore.fromSeed(seed, PolicyType.SINGLE_HD, ScriptType.P2PKH.getDefaultDerivation()).getKeyDerivation().getMasterFingerprint();
Wallet walletCopy = headersForm.getSigningWallet().copy();
OptionalInt optIndex = IntStream.range(0, walletCopy.getKeystores().size())
.filter(i -> walletCopy.getKeystores().get(i).getKeyDerivation().getMasterFingerprint().equals(masterFingerprint)).findFirst();
@@ -1044,7 +1044,7 @@ public class HeadersController extends TransactionFormController implements Init
keystore.setMasterPrivateExtendedKey(null);
});
Keystore original = walletCopy.getKeystores().get(optIndex.getAsInt());
- Keystore replacement = Keystore.fromSeed(seed, original.getKeyDerivation().getDerivation());
+ Keystore replacement = Keystore.fromSeed(seed, walletCopy.getPolicyType(), original.getKeyDerivation().getDerivation());
walletCopy.getKeystores().set(optIndex.getAsInt(), replacement);
signUnencryptedKeystores(walletCopy);
} else {
diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java
index 61eb295..827278c 100644
--- a/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java
+++ b/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java
@@ -656,7 +656,7 @@ public class KeystoreController extends WalletFormController implements Initiali
AppServices.showErrorDialog("Missing Script Type", "QR Code did not contain any information for the " + getWalletForm().getWallet().getScriptType().getDescription() + " script type.");
} else if(result.seed != null) {
try {
- Keystore keystore = Keystore.fromSeed(result.seed, getWalletForm().getWallet().getScriptType().getDefaultDerivation());
+ Keystore keystore = Keystore.fromSeed(result.seed, getWalletForm().getWallet().getPolicyType(), getWalletForm().getWallet().getScriptType().getDefaultDerivation());
fingerprint.setText(keystore.getKeyDerivation().getMasterFingerprint());
derivation.setText(keystore.getKeyDerivation().getDerivationPath());
xpub.setText(keystore.getExtendedPublicKey().toString());
diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java
index d52759c..1bdd5bf 100644
--- a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java
+++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsController.java
@@ -125,9 +125,7 @@ public class SettingsController extends WalletFormController implements Initiali
walletForm.getWallet().setPolicyType(policyType);
scriptType.setItems(FXCollections.observableArrayList(ScriptType.getAddressableScriptTypes(policyType)));
- if(!ScriptType.getAddressableScriptTypes(policyType).contains(walletForm.getWallet().getScriptType())) {
- scriptType.getSelectionModel().select(policyType.getDefaultScriptType());
- }
+ scriptType.getSelectionModel().select(policyType.getDefaultScriptType());
if(!initialising) {
clearKeystoreTabs();
diff --git a/src/test/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesigTest.java b/src/test/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesigTest.java
index 6a9937b..42e83e5 100644
--- a/src/test/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesigTest.java
+++ b/src/test/java/com/sparrowwallet/sparrow/io/CoboVaultSinglesigTest.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.ExtendedKey;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import org.junit.jupiter.api.Assertions;
@@ -10,7 +11,7 @@ public class CoboVaultSinglesigTest extends IoTest {
@Test
public void testImport() throws ImportException {
CoboVaultSinglesig coboSingleSig = new CoboVaultSinglesig();
- Keystore keystore = coboSingleSig.getKeystore(ScriptType.P2WPKH, getInputStream("cobo-singlesig-keystore-1.json"), null);
+ Keystore keystore = coboSingleSig.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH, getInputStream("cobo-singlesig-keystore-1.json"), null);
Assertions.assertEquals("Cobo Vault", keystore.getLabel());
Assertions.assertEquals("m/84'/0'/0'", keystore.getKeyDerivation().getDerivationPath());
@@ -22,6 +23,6 @@ public class CoboVaultSinglesigTest extends IoTest {
@Test
public void testIncorrectScriptType() throws ImportException {
CoboVaultSinglesig coboSingleSig = new CoboVaultSinglesig();
- Assertions.assertThrows(ImportException.class, () -> coboSingleSig.getKeystore(ScriptType.P2SH_P2WPKH, getInputStream("cobo-singlesig-keystore-1.json"), null));
+ Assertions.assertThrows(ImportException.class, () -> coboSingleSig.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2SH_P2WPKH, getInputStream("cobo-singlesig-keystore-1.json"), null));
}
}
diff --git a/src/test/java/com/sparrowwallet/sparrow/io/ColdcardMultisigTest.java b/src/test/java/com/sparrowwallet/sparrow/io/ColdcardMultisigTest.java
index 487facf..713bdef 100644
--- a/src/test/java/com/sparrowwallet/sparrow/io/ColdcardMultisigTest.java
+++ b/src/test/java/com/sparrowwallet/sparrow/io/ColdcardMultisigTest.java
@@ -19,7 +19,7 @@ public class ColdcardMultisigTest extends IoTest {
public void importKeystore1() throws ImportException {
Network.set(Network.TESTNET);
ColdcardMultisig ccMultisig = new ColdcardMultisig();
- Keystore keystore = ccMultisig.getKeystore(ScriptType.P2SH_P2WSH, getInputStream("cc-multisig-keystore-1.json"), null);
+ Keystore keystore = ccMultisig.getKeystore(PolicyType.MULTI_HD, ScriptType.P2SH_P2WSH, getInputStream("cc-multisig-keystore-1.json"), null);
Assertions.assertEquals("Coldcard", keystore.getLabel());
Assertions.assertEquals("m/48'/1'/0'/1'", keystore.getKeyDerivation().getDerivationPath());
Assertions.assertEquals("0f056943", keystore.getKeyDerivation().getMasterFingerprint());
@@ -30,14 +30,14 @@ public class ColdcardMultisigTest extends IoTest {
@Test
public void importKeystore1IncorrectScriptType() throws ImportException {
ColdcardMultisig ccMultisig = new ColdcardMultisig();
- Assertions.assertThrows(ImportException.class, () -> ccMultisig.getKeystore(ScriptType.P2SH_P2WPKH, getInputStream("cc-multisig-keystore-1.json"), null));
+ Assertions.assertThrows(ImportException.class, () -> ccMultisig.getKeystore(PolicyType.MULTI_HD, ScriptType.P2SH_P2WPKH, getInputStream("cc-multisig-keystore-1.json"), null));
}
@Test
public void importKeystore2() throws ImportException {
Network.set(Network.TESTNET);
ColdcardMultisig ccMultisig = new ColdcardMultisig();
- Keystore keystore = ccMultisig.getKeystore(ScriptType.P2SH, getInputStream("cc-multisig-keystore-2.json"), null);
+ Keystore keystore = ccMultisig.getKeystore(PolicyType.MULTI_HD, ScriptType.P2SH, getInputStream("cc-multisig-keystore-2.json"), null);
Assertions.assertEquals("Coldcard", keystore.getLabel());
Assertions.assertEquals("m/45'", keystore.getKeyDerivation().getDerivationPath());
Assertions.assertEquals("6ba6cfd0", keystore.getKeyDerivation().getMasterFingerprint());
@@ -49,7 +49,7 @@ public class ColdcardMultisigTest extends IoTest {
public void importKeystore2b() throws ImportException {
Network.set(Network.TESTNET);
ColdcardMultisig ccMultisig = new ColdcardMultisig();
- Keystore keystore = ccMultisig.getKeystore(ScriptType.P2WSH, getInputStream("cc-multisig-keystore-2.json"), null);
+ Keystore keystore = ccMultisig.getKeystore(PolicyType.MULTI_HD, ScriptType.P2WSH, getInputStream("cc-multisig-keystore-2.json"), null);
Assertions.assertEquals("Coldcard", keystore.getLabel());
Assertions.assertEquals("m/48'/1'/0'/2'", keystore.getKeyDerivation().getDerivationPath());
Assertions.assertEquals("6ba6cfd0", keystore.getKeyDerivation().getMasterFingerprint());
diff --git a/src/test/java/com/sparrowwallet/sparrow/io/ColdcardSinglesigTest.java b/src/test/java/com/sparrowwallet/sparrow/io/ColdcardSinglesigTest.java
index 113c9e5..0393053 100644
--- a/src/test/java/com/sparrowwallet/sparrow/io/ColdcardSinglesigTest.java
+++ b/src/test/java/com/sparrowwallet/sparrow/io/ColdcardSinglesigTest.java
@@ -2,7 +2,9 @@ package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.Network;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
+import com.sparrowwallet.drongo.silentpayments.SilentPaymentScanAddress;
import com.sparrowwallet.drongo.wallet.Keystore;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
@@ -13,7 +15,7 @@ public class ColdcardSinglesigTest extends IoTest {
public void testImport() throws ImportException {
Network.set(Network.TESTNET);
ColdcardSinglesig ccSingleSig = new ColdcardSinglesig();
- Keystore keystore = ccSingleSig.getKeystore(ScriptType.P2SH_P2WPKH, getInputStream("cc-singlesig-keystore-1.json"), null);
+ Keystore keystore = ccSingleSig.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2SH_P2WPKH, getInputStream("cc-singlesig-keystore-1.json"), null);
Assertions.assertEquals("Coldcard", keystore.getLabel());
Assertions.assertEquals("m/49'/1'/123'", keystore.getKeyDerivation().getDerivationPath());
@@ -26,7 +28,7 @@ public class ColdcardSinglesigTest extends IoTest {
public void testImportWitness() throws ImportException {
Network.set(Network.TESTNET);
ColdcardSinglesig ccSingleSig = new ColdcardSinglesig();
- Keystore keystore = ccSingleSig.getKeystore(ScriptType.P2WPKH, getInputStream("cc-singlesig-keystore-1.json"), null);
+ Keystore keystore = ccSingleSig.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH, getInputStream("cc-singlesig-keystore-1.json"), null);
Assertions.assertEquals("Coldcard", keystore.getLabel());
Assertions.assertEquals("m/84'/1'/123'", keystore.getKeyDerivation().getDerivationPath());
@@ -35,6 +37,22 @@ public class ColdcardSinglesigTest extends IoTest {
Assertions.assertTrue(keystore.isValid());
}
+ @Test
+ public void testImportSilentPayments() throws ImportException {
+ Network.set(Network.TESTNET);
+ ColdcardSinglesig ccSingleSig = new ColdcardSinglesig();
+ Keystore keystore = ccSingleSig.getKeystore(PolicyType.SINGLE_SP, ScriptType.P2TR, getInputStream("cc-singlesig-sp-keystore-1.json"), null);
+
+ Assertions.assertEquals("Coldcard", keystore.getLabel());
+ Assertions.assertEquals("m/352'/1'/0'", keystore.getKeyDerivation().getDerivationPath());
+ Assertions.assertEquals("0f056943", keystore.getKeyDerivation().getMasterFingerprint());
+ Assertions.assertNull(keystore.getExtendedPublicKey());
+ Assertions.assertNotNull(keystore.getSilentPaymentScanAddress());
+ Assertions.assertEquals(SilentPaymentScanAddress.fromKeyString("tspscan1q05wxw5wc7wqmkf8cnfc6ry76qej8vhr3a3mmxmwgv35s0tlw24fs82k0npv2hv6p97s8sd9t7vpf44kluka9w863zjwxzfrym2ay9ccfzt06c4"),
+ keystore.getSilentPaymentScanAddress());
+ Assertions.assertTrue(keystore.isValid());
+ }
+
@AfterEach
public void tearDown() throws Exception {
Network.set(null);
diff --git a/src/test/java/com/sparrowwallet/sparrow/io/KeystoneSinglesigTest.java b/src/test/java/com/sparrowwallet/sparrow/io/KeystoneSinglesigTest.java
index c8b8273..55cd089 100644
--- a/src/test/java/com/sparrowwallet/sparrow/io/KeystoneSinglesigTest.java
+++ b/src/test/java/com/sparrowwallet/sparrow/io/KeystoneSinglesigTest.java
@@ -1,6 +1,7 @@
package com.sparrowwallet.sparrow.io;
import com.sparrowwallet.drongo.ExtendedKey;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import org.junit.jupiter.api.Assertions;
@@ -10,7 +11,7 @@ public class KeystoneSinglesigTest extends IoTest {
@Test
public void testImport() throws ImportException {
KeystoneSinglesig keystoneSingleSig = new KeystoneSinglesig();
- Keystore keystore = keystoneSingleSig.getKeystore(ScriptType.P2WPKH, getInputStream("keystone-singlesig-keystore-1.txt"), null);
+ Keystore keystore = keystoneSingleSig.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH, getInputStream("keystone-singlesig-keystore-1.txt"), null);
Assertions.assertEquals("Keystone", keystore.getLabel());
Assertions.assertEquals("m/84'/0'/0'", keystore.getKeyDerivation().getDerivationPath());
@@ -22,6 +23,6 @@ public class KeystoneSinglesigTest extends IoTest {
@Test
public void testIncorrectScriptType() throws ImportException {
KeystoneSinglesig keystoneSingleSig = new KeystoneSinglesig();
- Assertions.assertThrows(ImportException.class, () -> keystoneSingleSig.getKeystore(ScriptType.P2SH_P2WPKH, getInputStream("keystone-singlesig-keystore-1.txt"), null));
+ Assertions.assertThrows(ImportException.class, () -> keystoneSingleSig.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2SH_P2WPKH, getInputStream("keystone-singlesig-keystore-1.txt"), null));
}
}
diff --git a/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java b/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java
index da63617..7afeeff 100644
--- a/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java
+++ b/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java
@@ -4,6 +4,7 @@ import com.google.common.io.ByteStreams;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.OutputDescriptor;
+import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
@@ -18,7 +19,7 @@ public class SpecterDIYTest extends IoTest {
public void testImport() throws ImportException {
Network.set(Network.TESTNET);
SpecterDIY specterDIY = new SpecterDIY();
- Keystore keystore = specterDIY.getKeystore(ScriptType.P2WPKH, getInputStream("specter-diy-keystore.txt"), null);
+ Keystore keystore = specterDIY.getKeystore(PolicyType.SINGLE_HD, ScriptType.P2WPKH, getInputStream("specter-diy-keystore.txt"), null);
Assertions.assertEquals("Specter DIY", keystore.getLabel());
Assertions.assertEquals("m/84'/1'/0'", keystore.getKeyDerivation().getDerivationPath());
diff --git a/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java b/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java
index 1aa89cb..1361a1d 100644
--- a/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java
+++ b/src/test/java/com/sparrowwallet/sparrow/io/StorageTest.java
@@ -34,7 +34,7 @@ public class StorageTest extends IoTest {
Keystore keystore = wallet.getKeystores().get(i);
if(keystore.hasSeed()) {
Keystore copyKeystore = copy.getKeystores().get(i);
- Keystore derivedKeystore = Keystore.fromSeed(copyKeystore.getSeed(), copyKeystore.getKeyDerivation().getDerivation());
+ Keystore derivedKeystore = Keystore.fromSeed(copyKeystore.getSeed(), wallet.getPolicyType(), copyKeystore.getKeyDerivation().getDerivation());
keystore.setKeyDerivation(derivedKeystore.getKeyDerivation());
keystore.setExtendedPublicKey(derivedKeystore.getExtendedPublicKey());
keystore.getSeed().setPassphrase(copyKeystore.getSeed().getPassphrase());
diff --git a/src/test/resources/com/sparrowwallet/sparrow/io/cc-singlesig-sp-keystore-1.json b/src/test/resources/com/sparrowwallet/sparrow/io/cc-singlesig-sp-keystore-1.json
new file mode 100644
index 0000000..58a00c4
--- /dev/null
+++ b/src/test/resources/com/sparrowwallet/sparrow/io/cc-singlesig-sp-keystore-1.json
@@ -0,0 +1,27 @@
+{
+ "chain": "XTN",
+ "xfp": "0F056943",
+ "xpub": "tpubD6NzVbkrYhZ4XzL5Dhayo67Gorv1YMS7j8pRUvVMd5odC2LBPLAygka9p7748JtSq82FNGPppFEz5xxZUdasBRCqJqXvUHq6xpnsMcYJzeh",
+ "account": 0,
+ "bip84": {
+ "_pub": "vpub5Y5a91QvDT3yog4bmgbqFo7GPXpRpozogzQeDArSPzsY8SKGHTgjSswhxhGkRonUQ9tyo9ZSQ1ecLKkVUyewWEUJZdwgUQycvG86FV7sdhZ",
+ "deriv": "m/84'/1'/0'",
+ "first": "tb1qupyd58ndsh7lut0et0vtrq432jvu9jtdyws9n9",
+ "name": "p2wpkh",
+ "xfp": "AB82D43E",
+ "xpub": "tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r"
+ },
+ "bip86": {
+ "deriv": "m/86'/1'/0'",
+ "first": "tb1prlna6c6us6jss2qyemcm8jpzjpuuyx46tz6pe80r6jmpf5dm3z7qnxwucf",
+ "name": "p2tr",
+ "xfp": "4A29873A",
+ "xpub": "tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1"
+ },
+ "bip352": {
+ "spscan": "tspscan1q05wxw5wc7wqmkf8cnfc6ry76qej8vhr3a3mmxmwgv35s0tlw24fs82k0npv2hv6p97s8sd9t7vpf44kluka9w863zjwxzfrym2ay9ccfzt06c4",
+ "deriv": "m/352'/1'/0'",
+ "name": "p2tr",
+ "xfp": "2A21A78D"
+ }
+}
Why this scored 33/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.