mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
add specter diy keystore import
This commit is contained in:
parent
ccead92388
commit
582065e7f0
10 changed files with 105 additions and 16 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit deb45687c08d4ff824ab7559233249c345d9c86a
|
Subproject commit 05674097428d25de043310f8ecddf06d998b3943
|
|
@ -668,7 +668,7 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean attemptImportWallet(File file, SecureString password) {
|
private boolean attemptImportWallet(File file, SecureString password) {
|
||||||
List<WalletImport> walletImporters = List.of(new ColdcardSinglesig(), new ColdcardMultisig(), new Electrum(), new Specter(), new CoboVaultSinglesig(), new CoboVaultMultisig());
|
List<WalletImport> walletImporters = List.of(new ColdcardSinglesig(), new ColdcardMultisig(), new Electrum(), new SpecterDesktop(), new CoboVaultSinglesig(), new CoboVaultMultisig());
|
||||||
for(WalletImport importer : walletImporters) {
|
for(WalletImport importer : walletImporters) {
|
||||||
try(FileInputStream inputStream = new FileInputStream(file)) {
|
try(FileInputStream inputStream = new FileInputStream(file)) {
|
||||||
if(importer.isEncrypted(file) && password == null) {
|
if(importer.isEncrypted(file) && password == null) {
|
||||||
|
|
|
@ -41,9 +41,9 @@ public class WalletExportDialog extends Dialog<Wallet> {
|
||||||
|
|
||||||
List<WalletExport> exporters;
|
List<WalletExport> exporters;
|
||||||
if(wallet.getPolicyType() == PolicyType.SINGLE) {
|
if(wallet.getPolicyType() == PolicyType.SINGLE) {
|
||||||
exporters = List.of(new Electrum(), new Specter());
|
exporters = List.of(new Electrum(), new SpecterDesktop());
|
||||||
} else if(wallet.getPolicyType() == PolicyType.MULTI) {
|
} else if(wallet.getPolicyType() == PolicyType.MULTI) {
|
||||||
exporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new Specter());
|
exporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new SpecterDesktop());
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException("Cannot export wallet with policy type " + wallet.getPolicyType());
|
throw new UnsupportedOperationException("Cannot export wallet with policy type " + wallet.getPolicyType());
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class WalletImportDialog extends Dialog<Wallet> {
|
||||||
importAccordion.getPanes().add(importPane);
|
importAccordion.getPanes().add(importPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<WalletImport> walletImporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new Specter());
|
List<WalletImport> walletImporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new SpecterDesktop());
|
||||||
for(WalletImport importer : walletImporters) {
|
for(WalletImport importer : walletImporters) {
|
||||||
FileWalletImportPane importPane = new FileWalletImportPane(importer);
|
FileWalletImportPane importPane = new FileWalletImportPane(importer);
|
||||||
importAccordion.getPanes().add(importPane);
|
importAccordion.getPanes().add(importPane);
|
||||||
|
|
64
src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java
Normal file
64
src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
|
import com.google.common.io.CharStreams;
|
||||||
|
import com.sparrowwallet.drongo.OutputDescriptor;
|
||||||
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
|
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
public class SpecterDIY implements KeystoreFileImport {
|
||||||
|
@Override
|
||||||
|
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||||
|
try {
|
||||||
|
String text = CharStreams.toString(new InputStreamReader(inputStream));
|
||||||
|
String outputDesc = "sh(" + text + ")";
|
||||||
|
OutputDescriptor outputDescriptor = OutputDescriptor.getOutputDescriptor(outputDesc);
|
||||||
|
Wallet wallet = outputDescriptor.toWallet();
|
||||||
|
|
||||||
|
if(wallet.getKeystores().size() != 1) {
|
||||||
|
throw new ImportException("Could not determine keystore from import");
|
||||||
|
}
|
||||||
|
|
||||||
|
Keystore keystore = wallet.getKeystores().get(0);
|
||||||
|
keystore.setLabel(getName());
|
||||||
|
keystore.setWalletModel(WalletModel.SPECTER_DIY);
|
||||||
|
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
|
||||||
|
|
||||||
|
return keystore;
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new ImportException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isKeystoreImportScannable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKeystoreImportDescription() {
|
||||||
|
return "Import file or QR created by using the Master Public Keys feature on your Specter DIY device. Note the default is P2WPKH for Single Signature, and P2WSH for Multi Signature.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEncrypted(File file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Specter DIY";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalletModel getWalletModel() {
|
||||||
|
return WalletModel.SPECTER_DIY;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class Specter implements WalletImport, WalletExport {
|
public class SpecterDesktop implements WalletImport, WalletExport {
|
||||||
@Override
|
@Override
|
||||||
public void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException {
|
public void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException {
|
||||||
try {
|
try {
|
||||||
|
@ -70,7 +70,7 @@ public class Specter implements WalletImport, WalletExport {
|
||||||
throw new ImportException(e);
|
throw new ImportException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ImportException("File was not a valid Specter wallet");
|
throw new ImportException("File was not a valid Specter Desktop wallet");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -85,12 +85,12 @@ public class Specter implements WalletImport, WalletExport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "Specter";
|
return "Specter Desktop";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WalletModel getWalletModel() {
|
public WalletModel getWalletModel() {
|
||||||
return WalletModel.SPECTER;
|
return WalletModel.SPECTER_DESKTOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SpecterWallet {
|
public static class SpecterWallet {
|
|
@ -16,9 +16,9 @@ public class HwAirgappedController extends KeystoreImportDetailController {
|
||||||
public void initializeView() {
|
public void initializeView() {
|
||||||
List<KeystoreFileImport> importers = Collections.emptyList();
|
List<KeystoreFileImport> importers = Collections.emptyList();
|
||||||
if(getMasterController().getWallet().getPolicyType().equals(PolicyType.SINGLE)) {
|
if(getMasterController().getWallet().getPolicyType().equals(PolicyType.SINGLE)) {
|
||||||
importers = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig());
|
importers = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new SpecterDIY());
|
||||||
} else if(getMasterController().getWallet().getPolicyType().equals(PolicyType.MULTI)) {
|
} else if(getMasterController().getWallet().getPolicyType().equals(PolicyType.MULTI)) {
|
||||||
importers = List.of(new ColdcardMultisig(), new CoboVaultMultisig());
|
importers = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new SpecterDIY());
|
||||||
}
|
}
|
||||||
|
|
||||||
for(KeystoreImport importer : importers) {
|
for(KeystoreImport importer : importers) {
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.ExtendedKey;
|
||||||
|
import com.sparrowwallet.drongo.Network;
|
||||||
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class SpecterDIYTest extends IoTest {
|
||||||
|
@Test
|
||||||
|
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);
|
||||||
|
|
||||||
|
Assert.assertEquals("Specter DIY", keystore.getLabel());
|
||||||
|
Assert.assertEquals("m/84'/1'/0'", keystore.getKeyDerivation().getDerivationPath());
|
||||||
|
Assert.assertEquals("b317ec86", keystore.getKeyDerivation().getMasterFingerprint());
|
||||||
|
Assert.assertEquals(ExtendedKey.fromDescriptor("vpub5YHLPnkkpPW1ecL7Di7Gv2wDHDtBNqRdt17gMULpxJ27ZA1MmW7xbZjdg1S7d5JKaJ8CiZEmRUHrEB6CGuLomA6ioVa1Pcke6fEb5CzDBU1"), keystore.getExtendedPublicKey());
|
||||||
|
Assert.assertTrue(keystore.isValid());
|
||||||
|
Network.set(Network.MAINNET);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,11 +6,11 @@ import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class SpecterTest extends IoTest {
|
public class SpecterDesktopTest extends IoTest {
|
||||||
@Test
|
@Test
|
||||||
public void testImport() throws ImportException {
|
public void testImport() throws ImportException {
|
||||||
Specter specter = new Specter();
|
SpecterDesktop specterDesktop = new SpecterDesktop();
|
||||||
Wallet wallet = specter.importWallet(getInputStream("specter-wallet.json"), null);
|
Wallet wallet = specterDesktop.importWallet(getInputStream("specter-wallet.json"), null);
|
||||||
|
|
||||||
Assert.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
|
Assert.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
|
||||||
Assert.assertEquals(ScriptType.P2SH_P2WPKH, wallet.getScriptType());
|
Assert.assertEquals(ScriptType.P2SH_P2WPKH, wallet.getScriptType());
|
||||||
|
@ -24,8 +24,8 @@ public class SpecterTest extends IoTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultisigImport() throws ImportException {
|
public void testMultisigImport() throws ImportException {
|
||||||
Specter specter = new Specter();
|
SpecterDesktop specterDesktop = new SpecterDesktop();
|
||||||
Wallet wallet = specter.importWallet(getInputStream("specter-multisig-wallet.json"), null);
|
Wallet wallet = specterDesktop.importWallet(getInputStream("specter-multisig-wallet.json"), null);
|
||||||
|
|
||||||
Assert.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
|
Assert.assertEquals(PolicyType.MULTI, wallet.getPolicyType());
|
||||||
Assert.assertEquals(ScriptType.P2WSH, wallet.getScriptType());
|
Assert.assertEquals(ScriptType.P2WSH, wallet.getScriptType());
|
|
@ -0,0 +1 @@
|
||||||
|
[b317ec86/84h/1h/0h]vpub5YHLPnkkpPW1ecL7Di7Gv2wDHDtBNqRdt17gMULpxJ27ZA1MmW7xbZjdg1S7d5JKaJ8CiZEmRUHrEB6CGuLomA6ioVa1Pcke6fEb5CzDBU1
|
Loading…
Reference in a new issue