Skip to content

Commit ce3cc2c

Browse files
committed
genimportscript: add Electrum format, write result to file
1 parent 0821c35 commit ce3cc2c

File tree

6 files changed

+69
-18
lines changed

6 files changed

+69
-18
lines changed

btc/bitcoind.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package btc
33
import (
44
"fmt"
55
"io"
6+
"strings"
67
"time"
78

89
"github.com/btcsuite/btcd/chaincfg"
@@ -16,6 +17,7 @@ const (
1617
FormatCli = "bitcoin-cli"
1718
FormatCliWatchOnly = "bitcoin-cli-watchonly"
1819
FormatImportwallet = "bitcoin-importwallet"
20+
FormatElectrum = "electrum"
1921
)
2022

2123
type KeyExporter interface {
@@ -40,6 +42,9 @@ func ParseFormat(format string) KeyExporter {
4042

4143
case FormatImportwallet:
4244
return &ImportWallet{}
45+
46+
case FormatElectrum:
47+
return &Electrum{}
4348
}
4449
}
4550

@@ -215,3 +220,35 @@ func (i *ImportWallet) Format(hdKey *hdkeychain.ExtendedKey,
215220
func (i *ImportWallet) Trailer(_ uint32) string {
216221
return ""
217222
}
223+
224+
type Electrum struct{}
225+
226+
func (p *Electrum) Header() string {
227+
return "# Copy the content of this file (without this line) into " +
228+
"Electrum."
229+
}
230+
231+
func (p *Electrum) Format(hdKey *hdkeychain.ExtendedKey,
232+
params *chaincfg.Params, path string, branch, index uint32) (string,
233+
error) {
234+
235+
privKey, err := hdKey.ECPrivKey()
236+
if err != nil {
237+
return "", fmt.Errorf("could not derive private key: %v", err)
238+
}
239+
wif, err := btcutil.NewWIF(privKey, params, true)
240+
if err != nil {
241+
return "", fmt.Errorf("could not encode WIF: %v", err)
242+
}
243+
244+
prefix := "p2wpkh"
245+
if strings.HasPrefix(path, lnd.WalletBIP49DerivationPath) {
246+
prefix = "p2wpkh-p2sh"
247+
}
248+
249+
return fmt.Sprintf("%s:%s", prefix, wif.String()), nil
250+
}
251+
252+
func (p *Electrum) Trailer(_ uint32) string {
253+
return ""
254+
}

cmd/chantools/genimportscript.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type genImportScriptCommand struct {
2121
DerivationPath string
2222
RecoveryWindow uint32
2323
RescanFrom uint32
24+
Stdout bool
2425

2526
rootKey *rootKey
2627
cmd *cobra.Command
@@ -46,16 +47,18 @@ The following script formats are currently supported:
4647
imported into bitcoind to watch the UTXOs of those keys. The funds cannot be
4748
spent that way as they are watch-only.
4849
* bitcoin-importwallet: Creates a text output that is compatible with
49-
bitcoind's importwallet command.`,
50+
bitcoind's importwallet command.
51+
* electrum: Creates a text output that contains one private key per line with
52+
the address type as the prefix, the way Electrum expects them.`,
5053
Example: `chantools genimportscript --format bitcoin-cli \
5154
--recoverywindow 5000`,
5255
RunE: cc.Execute,
5356
}
5457
cc.cmd.Flags().StringVar(
5558
&cc.Format, "format", "bitcoin-importwallet", "format of the "+
5659
"generated import script; currently supported are: "+
57-
"bitcoin-importwallet, bitcoin-cli and "+
58-
"bitcoin-cli-watchonly",
60+
"bitcoin-importwallet, bitcoin-cli, "+
61+
"bitcoin-cli-watchonly and electrum",
5962
)
6063
cc.cmd.Flags().BoolVar(
6164
&cc.LndPaths, "lndpaths", false, "use all derivation paths "+
@@ -79,6 +82,9 @@ The following script formats are currently supported:
7982
"from the wallet birthday if the lnd 24 word aezeed "+
8083
"is entered",
8184
)
85+
cc.cmd.Flags().BoolVar(
86+
&cc.Stdout, "stdout", false, "write generated import script "+
87+
"to standard out instead of writing it to a file")
8288

8389
cc.rootKey = newRootKey(cc.cmd, "decrypting the backup")
8490

@@ -137,10 +143,25 @@ func (c *genImportScriptCommand) Execute(_ *cobra.Command, _ []string) error {
137143
}
138144
}
139145

146+
writer := os.Stdout
147+
if !c.Stdout {
148+
fileName := fmt.Sprintf("results/genimportscript-%s.txt",
149+
time.Now().Format("2006-01-02-15-04-05"))
150+
log.Infof("Writing import script with format '%s' to %s",
151+
c.Format, fileName)
152+
153+
var err error
154+
writer, err = os.Create(fileName)
155+
if err != nil {
156+
return fmt.Errorf("error creating result file %s: %v",
157+
fileName, err)
158+
}
159+
}
160+
140161
exporter := btc.ParseFormat(c.Format)
141162
err = btc.ExportKeys(
142163
extendedKey, strPaths, paths, chainParams, c.RecoveryWindow,
143-
c.RescanFrom, exporter, os.Stdout,
164+
c.RescanFrom, exporter, writer,
144165
)
145166
if err != nil {
146167
return fmt.Errorf("error exporting keys: %v", err)

cmd/chantools/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626

2727
const (
2828
defaultAPIURL = "https://blockstream.info/api"
29-
version = "0.9.2"
29+
version = "0.9.3"
3030
na = "n/a"
3131

3232
Commit = ""

doc/chantools_fakechanbackup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ chantools fakechanbackup --from_channel_graph lncli_describegraph.json \
6161
--channelpoint string funding transaction outpoint of the channel to rescue (<txid>:<txindex>) as it is displayed on 1ml.com
6262
--from_channel_graph string the full LN channel graph in the JSON format that the 'lncli describegraph' returns
6363
-h, --help help for fakechanbackup
64-
--multi_file string the fake channel backup file to create (default "results/fake-2021-08-29-18-21-11.backup")
64+
--multi_file string the fake channel backup file to create (default "results/fake-2021-08-29-22-04-34.backup")
6565
--remote_node_addr string the remote node connection information in the format pubkey@host:port
6666
--rootkey string BIP32 HD root key of the wallet to use for encrypting the backup; leave empty to prompt for lnd 24 word aezeed
6767
--short_channel_id string the short channel ID in the format <blockheight>x<transactionindex>x<outputindex>

doc/chantools_genimportscript.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ The following script formats are currently supported:
1818
spent that way as they are watch-only.
1919
* bitcoin-importwallet: Creates a text output that is compatible with
2020
bitcoind's importwallet command.
21+
* electrum: Creates a text output that contains one private key per line with
22+
the address type as the prefix, the way Electrum expects them.
2123

2224
```
2325
chantools genimportscript [flags]
@@ -35,12 +37,13 @@ chantools genimportscript --format bitcoin-cli \
3537
```
3638
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
3739
--derivationpath string use one specific derivation path; specify the first levels of the derivation path before any internal/external branch; Cannot be used in conjunction with --lndpaths
38-
--format string format of the generated import script; currently supported are: bitcoin-importwallet, bitcoin-cli and bitcoin-cli-watchonly (default "bitcoin-importwallet")
40+
--format string format of the generated import script; currently supported are: bitcoin-importwallet, bitcoin-cli, bitcoin-cli-watchonly and electrum (default "bitcoin-importwallet")
3941
-h, --help help for genimportscript
4042
--lndpaths use all derivation paths that lnd used; results in a large number of results; cannot be used in conjunction with --derivationpath
4143
--recoverywindow uint32 number of keys to scan per internal/external branch; output will consist of double this amount of keys (default 2500)
4244
--rescanfrom uint32 block number to rescan from; will be set automatically from the wallet birthday if the lnd 24 word aezeed is entered (default 500000)
4345
--rootkey string BIP32 HD root key of the wallet to use for decrypting the backup; leave empty to prompt for lnd 24 word aezeed
46+
--stdout write generated import script to standard out instead of writing it to a file
4447
```
4548

4649
### Options inherited from parent commands

lnd/hdkeychain.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,9 @@ func AllDerivationPaths(params *chaincfg.Params) ([]string, [][]uint32, error) {
157157
)
158158
}
159159
pathStrings := []string{
160-
"m/44'/0'/0'",
161-
"m/49'/0'/0'",
160+
WalletBIP49DerivationPath,
162161
WalletDefaultDerivationPath,
163-
mkPath(keychain.KeyFamilyMultiSig),
164-
mkPath(keychain.KeyFamilyRevocationBase),
165-
mkPath(keychain.KeyFamilyHtlcBase),
166162
mkPath(keychain.KeyFamilyPaymentBase),
167-
mkPath(keychain.KeyFamilyDelayBase),
168-
mkPath(keychain.KeyFamilyRevocationRoot),
169-
mkPath(keychain.KeyFamilyNodeKey),
170-
mkPath(keychain.KeyFamilyStaticBackup),
171-
mkPath(keychain.KeyFamilyTowerSession),
172-
mkPath(keychain.KeyFamilyTowerID),
173163
}
174164
paths := make([][]uint32, len(pathStrings))
175165
for idx, path := range pathStrings {

0 commit comments

Comments
 (0)