From b3b1137030c480196513241aa9f82b49c7a1411c Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 16 Jun 2020 14:08:47 +0300 Subject: [PATCH] cli: allow to convert wallet from NEO2 to NEO3 format This command may be helpful to have during transition. --- cli/wallet/wallet.go | 56 +++++++++++++++++++++++++++++++++ pkg/encoding/address/address.go | 9 +++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/cli/wallet/wallet.go b/cli/wallet/wallet.go index 0e349c64a..2e91d9f6b 100644 --- a/cli/wallet/wallet.go +++ b/cli/wallet/wallet.go @@ -100,6 +100,18 @@ func NewCommands() []cli.Command { }, }, }, + { + Name: "convert", + Usage: "convert addresses from existing NEO2 NEP6-wallet to NEO3 format", + Action: convertWallet, + Flags: []cli.Flag{ + walletPathFlag, + cli.StringFlag{ + Name: "out, o", + Usage: "where to write converted wallet", + }, + }, + }, { Name: "create", Usage: "add an account to the existing wallet", @@ -233,6 +245,50 @@ func claimGas(ctx *cli.Context) error { return nil } +func convertWallet(ctx *cli.Context) error { + wall, err := openWallet(ctx.String("path")) + if err != nil { + return cli.NewExitError(err, 1) + } + defer wall.Close() + + newWallet, err := wallet.NewWallet(ctx.String("out")) + if err != nil { + return cli.NewExitError(err, -1) + } + defer newWallet.Close() + + for _, acc := range wall.Accounts { + address.Prefix = address.NEO2Prefix + + pass, err := readPassword(fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label)) + if err != nil { + return cli.NewExitError(err, -1) + } else if err := acc.Decrypt(pass); err != nil { + return cli.NewExitError("invalid passphrase", -1) + } + + address.Prefix = address.NEO3Prefix + newAcc, err := wallet.NewAccountFromWIF(acc.PrivateKey().WIF()) + if err != nil { + return cli.NewExitError(fmt.Errorf("can't convert account: %v", err), -1) + } + newAcc.Address = address.Uint160ToString(acc.Contract.ScriptHash()) + newAcc.Contract = acc.Contract + newAcc.Default = acc.Default + newAcc.Label = acc.Label + newAcc.Locked = acc.Locked + if err := newAcc.Encrypt(pass); err != nil { + return cli.NewExitError(fmt.Errorf("can't encrypt converted account: %v", err), -1) + } + newWallet.AddAccount(newAcc) + } + if err := newWallet.Save(); err != nil { + return cli.NewExitError(err, -1) + } + return nil +} + func addAccount(ctx *cli.Context) error { wall, err := openWallet(ctx.String("path")) if err != nil { diff --git a/pkg/encoding/address/address.go b/pkg/encoding/address/address.go index fc2ed4425..e0c6b6c4d 100644 --- a/pkg/encoding/address/address.go +++ b/pkg/encoding/address/address.go @@ -7,9 +7,16 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util" ) +const ( + // NEO2Prefix is the first byte of address for NEO2. + NEO2Prefix byte = 0x17 + // NEO3Prefix is the first byte of address for NEO3. + NEO3Prefix byte = 0x35 +) + // Prefix is the byte used to prepend to addresses when encoding them, it can // be changed and defaults to 23 (0x17), the standard NEO prefix. -var Prefix = byte(0x17) +var Prefix = NEO2Prefix // Uint160ToString returns the "NEO address" from the given Uint160. func Uint160ToString(u util.Uint160) string {