2019-07-13 00:41:32 +00:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
2019-10-08 09:17:03 +00:00
|
|
|
"encoding/hex"
|
2019-10-08 09:46:36 +00:00
|
|
|
"encoding/json"
|
2019-07-13 00:41:32 +00:00
|
|
|
"fmt"
|
2019-10-09 00:22:18 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"strings"
|
2019-07-13 00:41:32 +00:00
|
|
|
|
2019-12-19 20:13:17 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2019-10-18 04:47:41 +00:00
|
|
|
types "github.com/filecoin-project/lotus/chain/types"
|
2019-07-13 00:41:32 +00:00
|
|
|
"gopkg.in/urfave/cli.v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
var walletCmd = &cli.Command{
|
|
|
|
Name: "wallet",
|
|
|
|
Usage: "Manage wallet",
|
|
|
|
Subcommands: []*cli.Command{
|
|
|
|
walletNew,
|
|
|
|
walletList,
|
2019-07-18 20:26:04 +00:00
|
|
|
walletBalance,
|
2019-10-08 09:17:03 +00:00
|
|
|
walletExport,
|
|
|
|
walletImport,
|
2019-10-17 10:18:40 +00:00
|
|
|
walletGetDefault,
|
|
|
|
walletSetDefault,
|
2020-02-25 21:35:41 +00:00
|
|
|
walletSign,
|
2020-02-25 23:17:15 +00:00
|
|
|
walletVerify,
|
2019-07-13 00:41:32 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var walletNew = &cli.Command{
|
2019-10-09 20:02:08 +00:00
|
|
|
Name: "new",
|
|
|
|
Usage: "Generate a new key of the given type",
|
|
|
|
ArgsUsage: "[bls|secp256k1]",
|
2019-07-13 00:41:32 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
2019-07-13 00:41:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-18 23:16:23 +00:00
|
|
|
ctx := ReqContext(cctx)
|
2019-07-13 00:41:32 +00:00
|
|
|
|
|
|
|
t := cctx.Args().First()
|
|
|
|
if t == "" {
|
2020-01-08 19:16:09 +00:00
|
|
|
t = "secp256k1"
|
2019-07-13 00:41:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nk, err := api.WalletNew(ctx, t)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(nk.String())
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var walletList = &cli.Command{
|
|
|
|
Name: "list",
|
|
|
|
Usage: "List wallet address",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
2019-07-13 00:41:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-18 23:16:23 +00:00
|
|
|
ctx := ReqContext(cctx)
|
2019-07-13 00:41:32 +00:00
|
|
|
|
|
|
|
addrs, err := api.WalletList(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, addr := range addrs {
|
|
|
|
fmt.Println(addr.String())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2019-07-18 20:26:04 +00:00
|
|
|
|
|
|
|
var walletBalance = &cli.Command{
|
2019-10-09 20:02:08 +00:00
|
|
|
Name: "balance",
|
|
|
|
Usage: "Get account balance",
|
|
|
|
ArgsUsage: "[account address]",
|
2019-07-18 20:26:04 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
2019-07-18 20:26:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-18 23:16:23 +00:00
|
|
|
ctx := ReqContext(cctx)
|
2019-07-18 20:26:04 +00:00
|
|
|
|
2019-07-25 14:18:55 +00:00
|
|
|
var addr address.Address
|
|
|
|
if cctx.Args().First() != "" {
|
|
|
|
addr, err = address.NewFromString(cctx.Args().First())
|
|
|
|
} else {
|
|
|
|
addr, err = api.WalletDefaultAddress(ctx)
|
|
|
|
}
|
2019-07-18 20:26:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
balance, err := api.WalletBalance(ctx, addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-10-30 00:52:24 +00:00
|
|
|
fmt.Printf("%s\n", types.FIL(balance))
|
2019-07-18 20:26:04 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2019-10-08 09:17:03 +00:00
|
|
|
|
2019-10-17 10:18:40 +00:00
|
|
|
var walletGetDefault = &cli.Command{
|
|
|
|
Name: "default",
|
|
|
|
Usage: "Get default wallet address",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
addr, err := api.WalletDefaultAddress(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("%s\n", addr.String())
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var walletSetDefault = &cli.Command{
|
|
|
|
Name: "set-default",
|
|
|
|
Usage: "Set default wallet address",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
if !cctx.Args().Present() {
|
|
|
|
return fmt.Errorf("must pass address to set as default")
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := address.NewFromString(cctx.Args().First())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return api.WalletSetDefault(ctx, addr)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-10-08 09:17:03 +00:00
|
|
|
var walletExport = &cli.Command{
|
|
|
|
Name: "export",
|
|
|
|
Usage: "export keys",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
if !cctx.Args().Present() {
|
|
|
|
return fmt.Errorf("must specify key to export")
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := address.NewFromString(cctx.Args().First())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-10-08 09:46:36 +00:00
|
|
|
ki, err := api.WalletExport(ctx, addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := json.Marshal(ki)
|
2019-10-08 09:17:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(hex.EncodeToString(b))
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var walletImport = &cli.Command{
|
|
|
|
Name: "import",
|
|
|
|
Usage: "import keys",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
2019-11-12 20:00:40 +00:00
|
|
|
var hexdata []byte
|
2019-10-09 00:22:18 +00:00
|
|
|
if !cctx.Args().Present() || cctx.Args().First() == "-" {
|
|
|
|
indata, err := ioutil.ReadAll(os.Stdin)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-11-12 20:00:40 +00:00
|
|
|
hexdata = indata
|
2019-10-09 00:22:18 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
fdata, err := ioutil.ReadFile(cctx.Args().First())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-11-12 20:00:40 +00:00
|
|
|
hexdata = fdata
|
|
|
|
}
|
|
|
|
data, err := hex.DecodeString(strings.TrimSpace(string(hexdata)))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2019-10-08 09:17:03 +00:00
|
|
|
}
|
|
|
|
|
2019-10-08 09:46:36 +00:00
|
|
|
var ki types.KeyInfo
|
|
|
|
if err := json.Unmarshal(data, &ki); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := api.WalletImport(ctx, &ki)
|
2019-10-08 09:17:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-10-29 12:54:26 +00:00
|
|
|
fmt.Printf("imported key %s successfully!\n", addr)
|
2019-10-08 09:17:03 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-02-25 21:35:41 +00:00
|
|
|
|
|
|
|
var walletSign = &cli.Command{
|
|
|
|
Name: "sign",
|
|
|
|
Usage: "sign a message",
|
|
|
|
ArgsUsage: "<signing address> <hexMessage>",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
if !cctx.Args().Present() || cctx.NArg() != 2 {
|
|
|
|
return fmt.Errorf("must specify signing address and message to sign")
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := address.NewFromString(cctx.Args().First())
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
msg, err := hex.DecodeString(cctx.Args().Get(1))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
sig, err := api.WalletSign(ctx, addr, msg)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
sigBytes := append([]byte{byte(sig.TypeCode())}, sig.Data...)
|
|
|
|
|
|
|
|
fmt.Println(hex.EncodeToString(sigBytes))
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-02-25 23:17:15 +00:00
|
|
|
|
|
|
|
var walletVerify = &cli.Command{
|
|
|
|
Name: "verify",
|
|
|
|
Usage: "verify the signature of a message",
|
|
|
|
ArgsUsage: "<signing address> <hexMessage> <signature>",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetFullNodeAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
if !cctx.Args().Present() || cctx.NArg() != 3 {
|
|
|
|
return fmt.Errorf("must specify signing address, message, and signature to verify")
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := address.NewFromString(cctx.Args().First())
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
msg, err := hex.DecodeString(cctx.Args().Get(1))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
sigBytes, err := hex.DecodeString(cctx.Args().Get(2))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
sig, err := types.SignatureFromBytes(sigBytes)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if api.WalletVerify(ctx, addr, msg, &sig) {
|
|
|
|
fmt.Println("valid")
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
fmt.Println("invalid")
|
|
|
|
return NewCliError("CLI Verify called with invalid signature")
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|