diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WalletExportDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/WalletExportDialog.java index 2a4b463e..f52eb4df 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/WalletExportDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/WalletExportDialog.java @@ -43,7 +43,7 @@ public class WalletExportDialog extends Dialog { if(wallet.getPolicyType() == PolicyType.SINGLE) { exporters = List.of(new Electrum(), new SpecterDesktop(), new Sparrow()); } else if(wallet.getPolicyType() == PolicyType.MULTI) { - exporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new PassportMultisig(), new SpecterDesktop(), new BlueWalletMultisig(), new Sparrow()); + exporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new PassportMultisig(), new SpecterDesktop(), new BlueWalletMultisig(), new SpecterDIY(), new Sparrow()); } else { throw new UnsupportedOperationException("Cannot export wallet with policy type " + wallet.getPolicyType()); } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java index 9e2047e1..9422b138 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ColdcardMultisig.java @@ -180,7 +180,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle } try { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream)); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); writer.append("# " + getName() + " setup file (created by Sparrow)\n"); writer.append("#\n"); writer.append("Name: ").append(wallet.getName()).append("\n"); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java b/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java index e1fe2f2d..7df6f828 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/SpecterDIY.java @@ -10,13 +10,10 @@ import com.sparrowwallet.drongo.wallet.WalletModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.nio.charset.StandardCharsets; -public class SpecterDIY implements KeystoreFileImport { +public class SpecterDIY implements KeystoreFileImport, WalletExport { private static final Logger log = LoggerFactory.getLogger(SpecterDIY.class); @Override @@ -67,4 +64,36 @@ public class SpecterDIY implements KeystoreFileImport { public WalletModel getWalletModel() { return WalletModel.SPECTER_DIY; } + + @Override + public void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException { + try { + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); + writer.append("addwallet ").append(wallet.getName()).append("&").append(OutputDescriptor.getOutputDescriptor(wallet).toString().replace('\'', 'h')).append("\n"); + writer.flush(); + } catch(Exception e) { + log.error("Error exporting Specter DIY wallet", e); + throw new ExportException("Error exporting Specter DIY wallet", e); + } + } + + @Override + public String getWalletExportDescription() { + return "Export file or QR that can be read by your Specter DIY using the Wallets > Add Wallet feature."; + } + + @Override + public String getExportFileExtension(Wallet wallet) { + return "txt"; + } + + @Override + public boolean isWalletExportScannable() { + return true; + } + + @Override + public boolean walletExportRequiresDecryption() { + return false; + } } diff --git a/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java b/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java index 9e40e703..266dbfa8 100644 --- a/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java +++ b/src/test/java/com/sparrowwallet/sparrow/io/SpecterDIYTest.java @@ -1,12 +1,18 @@ package com.sparrowwallet.sparrow.io; +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.protocol.ScriptType; import com.sparrowwallet.drongo.wallet.Keystore; +import com.sparrowwallet.drongo.wallet.Wallet; import org.junit.Assert; import org.junit.Test; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + public class SpecterDIYTest extends IoTest { @Test public void testImport() throws ImportException { @@ -21,4 +27,20 @@ public class SpecterDIYTest extends IoTest { Assert.assertTrue(keystore.isValid()); Network.set(Network.MAINNET); } + + @Test + public void testExport() throws ExportException, IOException { + OutputDescriptor walletDescriptor = OutputDescriptor.getOutputDescriptor("wsh(sortedmulti(2,[7fd1bbf4/48h/0h/0h/2h]xpub6DnVFCXjZKhSAJw1oGzksdc1CtMxHxqG6DgNSjZHsymMSgcNEb2c3bz5N2bBMEEUFos98CeAWbh1pTMBcJrsKW63icdAQNGT6Aqv1WWrkxg,[8ff26349/48h/0h/0h/2h]xpub6ErPooPdSeBoXVZocBe8EWF9GXjFuV52kme35p4MtrP2SAFdUmgTJM1urrJzSuA44izrEuiQNNdmWEVRaBJcBDcPpnLBR8tP2Pcu2EiyeHu,[ff3305c2/48h/0h/0h/2h]xpub6Dpndp2xurqbfSGhxKVXzk3nJZgah3PdD3qD11KyPicYYBatRxfxqoN7s9tnWKXaz7zhyVqcvnJyak7BVKonW2wTXHd1zNDxJAu8jcxF59j))"); + Wallet wallet = walletDescriptor.toWallet(); + wallet.setName("Sparrow Multisig"); + + SpecterDIY specterDIY = new SpecterDIY(); + byte[] walletBytes = ByteStreams.toByteArray(getInputStream("specter-diy-export.txt")); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + specterDIY.exportWallet(wallet, baos); + String original = new String(walletBytes); + String exported = new String(baos.toByteArray()); + + Assert.assertEquals(original, exported); + } } diff --git a/src/test/resources/com/sparrowwallet/sparrow/io/specter-diy-export.txt b/src/test/resources/com/sparrowwallet/sparrow/io/specter-diy-export.txt new file mode 100644 index 00000000..69c6aea1 --- /dev/null +++ b/src/test/resources/com/sparrowwallet/sparrow/io/specter-diy-export.txt @@ -0,0 +1 @@ +addwallet Sparrow Multisig&wsh(sortedmulti(2,[7fd1bbf4/48h/0h/0h/2h]xpub6DnVFCXjZKhSAJw1oGzksdc1CtMxHxqG6DgNSjZHsymMSgcNEb2c3bz5N2bBMEEUFos98CeAWbh1pTMBcJrsKW63icdAQNGT6Aqv1WWrkxg,[8ff26349/48h/0h/0h/2h]xpub6ErPooPdSeBoXVZocBe8EWF9GXjFuV52kme35p4MtrP2SAFdUmgTJM1urrJzSuA44izrEuiQNNdmWEVRaBJcBDcPpnLBR8tP2Pcu2EiyeHu,[ff3305c2/48h/0h/0h/2h]xpub6Dpndp2xurqbfSGhxKVXzk3nJZgah3PdD3qD11KyPicYYBatRxfxqoN7s9tnWKXaz7zhyVqcvnJyak7BVKonW2wTXHd1zNDxJAu8jcxF59j))