mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2026-07-30 19:46:16 +00:00
support retrieving silent payments spscan keys via connected devices
This commit is contained in:
+1
-1
Submodule lark updated: a6371b74df...45e7a2f97e
@@ -12,6 +12,7 @@ import com.sparrowwallet.drongo.policy.PolicyType;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
import com.sparrowwallet.drongo.silentpayments.SilentPaymentScanAddress;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
@@ -730,13 +731,21 @@ public class DevicePane extends TitledDescriptionPane {
|
||||
}
|
||||
}
|
||||
|
||||
importXpub(derivation);
|
||||
importKey(derivation);
|
||||
});
|
||||
enumerateService.setOnFailed(workerStateEvent -> {
|
||||
setError("Error", enumerateService.getException().getMessage());
|
||||
importButton.setDisable(false);
|
||||
});
|
||||
enumerateService.start();
|
||||
} else {
|
||||
importKey(derivation);
|
||||
}
|
||||
}
|
||||
|
||||
private void importKey(List<ChildNumber> derivation) {
|
||||
if(wallet != null && wallet.getPolicyType() == PolicyType.SINGLE_SP) {
|
||||
importSpscan(derivation);
|
||||
} else {
|
||||
importXpub(derivation);
|
||||
}
|
||||
@@ -771,6 +780,35 @@ public class DevicePane extends TitledDescriptionPane {
|
||||
getXpubService.start();
|
||||
}
|
||||
|
||||
private void importSpscan(List<ChildNumber> derivation) {
|
||||
String derivationPath = KeyDerivation.writePath(derivation);
|
||||
|
||||
Hwi.GetSpscanService getSpscanService = new Hwi.GetSpscanService(device, passphrase.get(), derivationPath);
|
||||
getSpscanService.setOnSucceeded(workerStateEvent -> {
|
||||
SilentPaymentScanAddress spscan = getSpscanService.getValue();
|
||||
|
||||
try {
|
||||
Keystore keystore = new Keystore();
|
||||
keystore.setLabel(device.getModel().toDisplayString());
|
||||
keystore.setSource(KeystoreSource.HW_USB);
|
||||
keystore.setWalletModel(device.getModel());
|
||||
keystore.setKeyDerivation(new KeyDerivation(device.getFingerprint(), derivationPath));
|
||||
keystore.setSilentPaymentScanAddress(spscan);
|
||||
|
||||
importKeystore(derivation, keystore);
|
||||
} catch(Exception e) {
|
||||
setError("Could not retrieve spscan", e.getMessage());
|
||||
}
|
||||
});
|
||||
getSpscanService.setOnFailed(workerStateEvent -> {
|
||||
setError("Could not retrieve spscan", getSpscanService.getException().getMessage());
|
||||
importButton.setDisable(false);
|
||||
});
|
||||
setDescription("Importing...");
|
||||
showHideLink.setVisible(false);
|
||||
getSpscanService.start();
|
||||
}
|
||||
|
||||
private void importKeystore(List<ChildNumber> derivation, Keystore keystore) {
|
||||
if(wallet.getScriptType() == null) {
|
||||
ScriptType scriptType = Arrays.stream(ScriptType.ADDRESSABLE_TYPES).filter(type -> type.getDefaultDerivation().get(0).equals(derivation.get(0))).findFirst().orElse(ScriptType.P2PKH);
|
||||
@@ -1179,7 +1217,7 @@ public class DevicePane extends TitledDescriptionPane {
|
||||
showHideLink.setVisible(true);
|
||||
setExpanded(false);
|
||||
List<ChildNumber> importDerivation = KeyDerivation.parsePath(derivationField.getText());
|
||||
importXpub(importDerivation);
|
||||
importKey(importDerivation);
|
||||
});
|
||||
|
||||
derivationField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.sparrowwallet.drongo.OsType;
|
||||
import com.sparrowwallet.drongo.OutputDescriptor;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
import com.sparrowwallet.drongo.silentpayments.SilentPaymentScanAddress;
|
||||
import com.sparrowwallet.drongo.wallet.StandardAccount;
|
||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||
import com.sparrowwallet.lark.DeviceException;
|
||||
@@ -167,6 +168,20 @@ public class Hwi {
|
||||
}
|
||||
}
|
||||
|
||||
public SilentPaymentScanAddress getSpscan(Device device, String passphrase, String derivationPath) throws ImportException {
|
||||
try {
|
||||
Lark lark = getLark(passphrase);
|
||||
SilentPaymentScanAddress spscan = lark.getSpscanAtPath(device.getType(), device.getPath(), derivationPath);
|
||||
isPromptActive = false;
|
||||
return spscan;
|
||||
} catch(DeviceException e) {
|
||||
throw new ImportException(e.getMessage(), e);
|
||||
} catch(RuntimeException e) {
|
||||
log.error("Error retrieving spscan", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public String displayAddress(Device device, String passphrase, ScriptType scriptType, OutputDescriptor addressDescriptor,
|
||||
OutputDescriptor walletDescriptor, String walletName, byte[] walletRegistration) throws DisplayAddressException {
|
||||
try {
|
||||
@@ -443,6 +458,28 @@ public class Hwi {
|
||||
}
|
||||
}
|
||||
|
||||
public static class GetSpscanService extends Service<SilentPaymentScanAddress> {
|
||||
private final Device device;
|
||||
private final String passphrase;
|
||||
private final String derivationPath;
|
||||
|
||||
public GetSpscanService(Device device, String passphrase, String derivationPath) {
|
||||
this.device = device;
|
||||
this.passphrase = passphrase;
|
||||
this.derivationPath = derivationPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<SilentPaymentScanAddress> createTask() {
|
||||
return new Task<>() {
|
||||
protected SilentPaymentScanAddress call() throws ImportException {
|
||||
Hwi hwi = new Hwi();
|
||||
return hwi.getSpscan(device, passphrase, derivationPath);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class GetXpubsService extends Service<Map<WalletType, String>> {
|
||||
private final Device device;
|
||||
private final String passphrase;
|
||||
|
||||
@@ -54,6 +54,10 @@ public class Tapsigner implements KeystoreCardImport {
|
||||
|
||||
@Override
|
||||
public Keystore getKeystore(PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
|
||||
if(policyType == PolicyType.SINGLE_SP) {
|
||||
throw new ImportException(getName() + " does not support receiving silent payments");
|
||||
}
|
||||
|
||||
if(pin.length() < 6) {
|
||||
throw new ImportException("PIN too short.");
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ public class Keycard implements KeystoreCardImport {
|
||||
|
||||
@Override
|
||||
public Keystore getKeystore(PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
|
||||
if(policyType == PolicyType.SINGLE_SP) {
|
||||
throw new ImportException(getName() + " does not support receiving silent payments");
|
||||
}
|
||||
|
||||
if(!StringUtils.isNumeric(pin)) {
|
||||
throw new ImportException("PIN must be all digits.");
|
||||
}
|
||||
|
||||
@@ -53,6 +53,10 @@ public class Satochip implements KeystoreCardImport {
|
||||
|
||||
@Override
|
||||
public Keystore getKeystore(PolicyType policyType, String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException {
|
||||
if(policyType == PolicyType.SINGLE_SP) {
|
||||
throw new ImportException(getName() + " does not support receiving silent payments");
|
||||
}
|
||||
|
||||
if(pin.length() < 4) {
|
||||
throw new ImportException("PIN too short.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user