|
|
@ -4,18 +4,20 @@ import com.sparrowwallet.drongo.ExtendedKey; |
|
|
|
import com.sparrowwallet.drongo.KeyPurpose; |
|
|
|
import com.sparrowwallet.drongo.policy.PolicyType; |
|
|
|
import com.sparrowwallet.drongo.protocol.ScriptType; |
|
|
|
import com.sparrowwallet.drongo.wallet.Keystore; |
|
|
|
import com.sparrowwallet.drongo.wallet.Wallet; |
|
|
|
import com.sparrowwallet.drongo.wallet.WalletModel; |
|
|
|
import com.sparrowwallet.drongo.wallet.WalletNode; |
|
|
|
import com.sparrowwallet.drongo.wallet.*; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
|
|
|
|
import java.io.BufferedWriter; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.OutputStream; |
|
|
|
import java.io.OutputStreamWriter; |
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.util.Iterator; |
|
|
|
|
|
|
|
public class ElectrumPersonalServer implements WalletExport { |
|
|
|
private static final Logger log = LoggerFactory.getLogger(ElectrumPersonalServer.class); |
|
|
|
|
|
|
|
@Override |
|
|
|
public String getName() { |
|
|
|
return "Electrum Personal Server"; |
|
|
@ -37,58 +39,73 @@ public class ElectrumPersonalServer implements WalletExport { |
|
|
|
writer.write("# Electrum Personal Server configuration file fragments\n"); |
|
|
|
writer.write("# Copy the lines below into the relevant sections in your EPS config.ini file\n\n"); |
|
|
|
writer.write("# Copy into [master-public-keys] section\n"); |
|
|
|
writer.write(wallet.getFullName().replace(' ', '_') + " = "); |
|
|
|
|
|
|
|
ExtendedKey.Header xpubHeader = ExtendedKey.Header.fromScriptType(wallet.getScriptType(), false); |
|
|
|
if(wallet.getPolicyType() == PolicyType.MULTI) { |
|
|
|
writer.write(wallet.getDefaultPolicy().getNumSignaturesRequired() + " "); |
|
|
|
Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet(); |
|
|
|
writeWalletXpub(masterWallet, writer); |
|
|
|
for(Wallet childWallet : masterWallet.getChildWallets()) { |
|
|
|
if(!childWallet.isNested()) { |
|
|
|
writeWalletXpub(childWallet, writer); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for(Iterator<Keystore> iter = wallet.getKeystores().iterator(); iter.hasNext(); ) { |
|
|
|
Keystore keystore = iter.next(); |
|
|
|
writer.write(keystore.getExtendedPublicKey().toString(xpubHeader)); |
|
|
|
writeBip47Addresses(masterWallet, writer); |
|
|
|
|
|
|
|
if(iter.hasNext()) { |
|
|
|
writer.write(" "); |
|
|
|
} |
|
|
|
writer.flush(); |
|
|
|
} catch(Exception e) { |
|
|
|
log.error("Could not export EPS wallet", e); |
|
|
|
throw new ExportException("Could not export EPS wallet", e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static void writeWalletXpub(Wallet wallet, BufferedWriter writer) throws IOException { |
|
|
|
writer.write(wallet.getFullName().replace(' ', '_') + " = "); |
|
|
|
|
|
|
|
ExtendedKey.Header xpubHeader = ExtendedKey.Header.fromScriptType(wallet.getScriptType(), false); |
|
|
|
if(wallet.getPolicyType() == PolicyType.MULTI) { |
|
|
|
writer.write(wallet.getDefaultPolicy().getNumSignaturesRequired() + " "); |
|
|
|
} |
|
|
|
|
|
|
|
for(Iterator<Keystore> iter = wallet.getKeystores().iterator(); iter.hasNext(); ) { |
|
|
|
Keystore keystore = iter.next(); |
|
|
|
writer.write(keystore.getExtendedPublicKey().toString(xpubHeader)); |
|
|
|
|
|
|
|
if(iter.hasNext()) { |
|
|
|
writer.write(" "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
writer.newLine(); |
|
|
|
|
|
|
|
if(wallet.hasPaymentCode()) { |
|
|
|
writer.write("\n# Copy into [watch-only-addresses] section\n"); |
|
|
|
WalletNode notificationNode = wallet.getNotificationWallet().getNode(KeyPurpose.NOTIFICATION); |
|
|
|
writer.write(wallet.getFullName().replace(' ', '_') + "-notification_addr = " + notificationNode.getAddress().toString() + "\n"); |
|
|
|
|
|
|
|
for(Wallet childWallet : wallet.getChildWallets()) { |
|
|
|
if(childWallet.isBip47()) { |
|
|
|
writer.write(childWallet.getFullName().replace(' ', '_') + " = "); |
|
|
|
for(Iterator<KeyPurpose> purposeIterator = KeyPurpose.DEFAULT_PURPOSES.iterator(); purposeIterator.hasNext(); ) { |
|
|
|
KeyPurpose keyPurpose = purposeIterator.next(); |
|
|
|
for(Iterator<WalletNode> iter = childWallet.getNode(keyPurpose).getChildren().iterator(); iter.hasNext(); ) { |
|
|
|
WalletNode receiveNode = iter.next(); |
|
|
|
writer.write(receiveNode.getAddress().toString()); |
|
|
|
|
|
|
|
if(iter.hasNext()) { |
|
|
|
writer.write(" "); |
|
|
|
} |
|
|
|
} |
|
|
|
writer.newLine(); |
|
|
|
} |
|
|
|
|
|
|
|
if(purposeIterator.hasNext()) { |
|
|
|
private static void writeBip47Addresses(Wallet wallet, BufferedWriter writer) throws IOException { |
|
|
|
if(wallet.hasPaymentCode()) { |
|
|
|
writer.write("\n# Copy into [watch-only-addresses] section\n"); |
|
|
|
WalletNode notificationNode = wallet.getNotificationWallet().getNode(KeyPurpose.NOTIFICATION); |
|
|
|
writer.write(wallet.getFullName().replace(' ', '_') + "-notification_addr = " + notificationNode.getAddress().toString() + "\n"); |
|
|
|
|
|
|
|
for(Wallet childWallet : wallet.getChildWallets()) { |
|
|
|
if(childWallet.isBip47()) { |
|
|
|
writer.write(childWallet.getFullName().replace(' ', '_') + " = "); |
|
|
|
for(Iterator<KeyPurpose> purposeIterator = KeyPurpose.DEFAULT_PURPOSES.iterator(); purposeIterator.hasNext(); ) { |
|
|
|
KeyPurpose keyPurpose = purposeIterator.next(); |
|
|
|
for(Iterator<WalletNode> iter = childWallet.getNode(keyPurpose).getChildren().iterator(); iter.hasNext(); ) { |
|
|
|
WalletNode receiveNode = iter.next(); |
|
|
|
writer.write(receiveNode.getAddress().toString()); |
|
|
|
|
|
|
|
if(iter.hasNext()) { |
|
|
|
writer.write(" "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
writer.newLine(); |
|
|
|
if(purposeIterator.hasNext()) { |
|
|
|
writer.write(" "); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
writer.write("\n# Important: If this wallet receives any BIP47 payments, redo this export"); |
|
|
|
writer.newLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
writer.flush(); |
|
|
|
} catch(Exception e) { |
|
|
|
throw new ExportException("Could not export wallet", e); |
|
|
|
writer.write("\n# Important: If this wallet receives any BIP47 payments, redo this export"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -111,4 +128,9 @@ public class ElectrumPersonalServer implements WalletExport { |
|
|
|
public boolean walletExportRequiresDecryption() { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public boolean exportsAllWallets() { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|