2019-08-07 23:22:35 +00:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
2020-07-23 02:30:51 +00:00
|
|
|
"encoding/hex"
|
2019-08-07 23:22:35 +00:00
|
|
|
"fmt"
|
2022-09-01 14:30:36 +00:00
|
|
|
"strings"
|
2019-10-03 18:12:30 +00:00
|
|
|
|
2020-08-12 17:06:08 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
2021-02-23 14:50:47 +00:00
|
|
|
"golang.org/x/xerrors"
|
2020-08-12 17:06:08 +00:00
|
|
|
|
2019-12-19 20:13:17 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2020-09-07 03:49:10 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
2020-08-12 17:06:08 +00:00
|
|
|
|
2020-12-25 08:25:46 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2019-08-07 23:22:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var sendCmd = &cli.Command{
|
2019-10-09 20:02:08 +00:00
|
|
|
Name: "send",
|
|
|
|
Usage: "Send funds between accounts",
|
2020-03-04 21:46:00 +00:00
|
|
|
ArgsUsage: "[targetAddress] [amount]",
|
2019-08-07 23:22:35 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
2020-07-16 00:55:27 +00:00
|
|
|
Name: "from",
|
2020-01-21 19:02:51 +00:00
|
|
|
Usage: "optionally specify the account to send funds from",
|
2019-08-07 23:22:35 +00:00
|
|
|
},
|
2020-04-01 01:34:23 +00:00
|
|
|
&cli.StringFlag{
|
2020-08-06 21:08:42 +00:00
|
|
|
Name: "gas-premium",
|
2020-04-01 01:34:23 +00:00
|
|
|
Usage: "specify gas price to use in AttoFIL",
|
|
|
|
Value: "0",
|
|
|
|
},
|
2020-08-06 21:08:42 +00:00
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "gas-feecap",
|
|
|
|
Usage: "specify gas fee cap to use in AttoFIL",
|
|
|
|
Value: "0",
|
|
|
|
},
|
2020-07-24 00:23:48 +00:00
|
|
|
&cli.Int64Flag{
|
|
|
|
Name: "gas-limit",
|
|
|
|
Usage: "specify gas limit",
|
|
|
|
Value: 0,
|
|
|
|
},
|
2020-12-03 17:36:34 +00:00
|
|
|
&cli.Uint64Flag{
|
2020-04-01 20:26:14 +00:00
|
|
|
Name: "nonce",
|
|
|
|
Usage: "specify the nonce to use",
|
2020-12-03 17:36:34 +00:00
|
|
|
Value: 0,
|
2020-04-01 20:26:14 +00:00
|
|
|
},
|
2020-07-23 02:30:51 +00:00
|
|
|
&cli.Uint64Flag{
|
|
|
|
Name: "method",
|
|
|
|
Usage: "specify method to invoke",
|
2020-12-25 08:25:46 +00:00
|
|
|
Value: uint64(builtin.MethodSend),
|
2020-07-23 02:30:51 +00:00
|
|
|
},
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "params-json",
|
|
|
|
Usage: "specify invocation parameters in json",
|
|
|
|
},
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "params-hex",
|
|
|
|
Usage: "specify invocation parameters in hex",
|
|
|
|
},
|
2020-12-25 08:25:46 +00:00
|
|
|
&cli.BoolFlag{
|
2021-01-06 03:37:29 +00:00
|
|
|
Name: "force",
|
2021-03-25 14:24:09 +00:00
|
|
|
Usage: "Deprecated: use global 'force-send'",
|
2020-12-25 08:25:46 +00:00
|
|
|
},
|
2019-08-07 23:22:35 +00:00
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
2021-03-25 14:24:09 +00:00
|
|
|
if cctx.IsSet("force") {
|
|
|
|
fmt.Println("'force' flag is deprecated, use global flag 'force-send'")
|
|
|
|
}
|
|
|
|
|
2020-07-23 19:31:28 +00:00
|
|
|
if cctx.Args().Len() != 2 {
|
|
|
|
return ShowHelp(cctx, fmt.Errorf("'send' expects two arguments, target and amount"))
|
|
|
|
}
|
|
|
|
|
2021-02-23 14:50:47 +00:00
|
|
|
srv, err := GetFullNodeServices(cctx)
|
2019-08-07 23:22:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-23 14:50:47 +00:00
|
|
|
defer srv.Close() //nolint:errcheck
|
2019-08-07 23:22:35 +00:00
|
|
|
|
|
|
|
ctx := ReqContext(cctx)
|
2021-02-23 14:50:47 +00:00
|
|
|
var params SendParams
|
2019-08-07 23:22:35 +00:00
|
|
|
|
2021-02-23 14:50:47 +00:00
|
|
|
params.To, err = address.NewFromString(cctx.Args().Get(0))
|
2019-08-07 23:22:35 +00:00
|
|
|
if err != nil {
|
2020-07-23 19:31:28 +00:00
|
|
|
return ShowHelp(cctx, fmt.Errorf("failed to parse target address: %w", err))
|
2019-08-07 23:22:35 +00:00
|
|
|
}
|
|
|
|
|
2019-10-18 12:31:45 +00:00
|
|
|
val, err := types.ParseFIL(cctx.Args().Get(1))
|
2019-08-07 23:22:35 +00:00
|
|
|
if err != nil {
|
2020-07-23 19:31:28 +00:00
|
|
|
return ShowHelp(cctx, fmt.Errorf("failed to parse amount: %w", err))
|
2019-08-07 23:22:35 +00:00
|
|
|
}
|
2021-02-23 14:50:47 +00:00
|
|
|
params.Val = abi.TokenAmount(val)
|
2019-08-07 23:22:35 +00:00
|
|
|
|
2021-02-23 14:50:47 +00:00
|
|
|
if from := cctx.String("from"); from != "" {
|
|
|
|
addr, err := address.NewFromString(from)
|
2019-08-07 23:22:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-23 14:50:47 +00:00
|
|
|
params.From = addr
|
|
|
|
}
|
|
|
|
|
|
|
|
if cctx.IsSet("gas-premium") {
|
|
|
|
gp, err := types.BigFromString(cctx.String("gas-premium"))
|
2021-02-10 15:46:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-23 14:50:47 +00:00
|
|
|
params.GasPremium = &gp
|
2021-02-10 15:46:21 +00:00
|
|
|
}
|
|
|
|
|
2021-02-23 14:50:47 +00:00
|
|
|
if cctx.IsSet("gas-feecap") {
|
|
|
|
gfc, err := types.BigFromString(cctx.String("gas-feecap"))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
params.GasFeeCap = &gfc
|
2021-02-23 14:25:19 +00:00
|
|
|
}
|
2021-02-23 14:50:47 +00:00
|
|
|
|
|
|
|
if cctx.IsSet("gas-limit") {
|
|
|
|
limit := cctx.Int64("gas-limit")
|
|
|
|
params.GasLimit = &limit
|
2020-08-06 21:08:42 +00:00
|
|
|
}
|
2020-04-01 01:34:23 +00:00
|
|
|
|
2021-02-23 14:50:47 +00:00
|
|
|
params.Method = abi.MethodNum(cctx.Uint64("method"))
|
2020-07-23 02:30:51 +00:00
|
|
|
|
|
|
|
if cctx.IsSet("params-json") {
|
2021-02-23 14:50:47 +00:00
|
|
|
decparams, err := srv.DecodeTypedParamsFromJSON(ctx, params.To, params.Method, cctx.String("params-json"))
|
2020-07-23 02:30:51 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to decode json params: %w", err)
|
|
|
|
}
|
2021-02-23 14:50:47 +00:00
|
|
|
params.Params = decparams
|
2020-07-23 02:30:51 +00:00
|
|
|
}
|
|
|
|
if cctx.IsSet("params-hex") {
|
2021-02-23 14:50:47 +00:00
|
|
|
if params.Params != nil {
|
2020-07-23 02:30:51 +00:00
|
|
|
return fmt.Errorf("can only specify one of 'params-json' and 'params-hex'")
|
|
|
|
}
|
|
|
|
decparams, err := hex.DecodeString(cctx.String("params-hex"))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to decode hex params: %w", err)
|
|
|
|
}
|
2021-02-23 14:50:47 +00:00
|
|
|
params.Params = decparams
|
2020-07-23 02:30:51 +00:00
|
|
|
}
|
2021-01-28 20:33:41 +00:00
|
|
|
|
2021-02-23 14:50:47 +00:00
|
|
|
if cctx.IsSet("nonce") {
|
|
|
|
n := cctx.Uint64("nonce")
|
|
|
|
params.Nonce = &n
|
2019-08-07 23:22:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-24 14:12:35 +00:00
|
|
|
proto, err := srv.MessageForSend(ctx, params)
|
2021-02-23 14:50:47 +00:00
|
|
|
if err != nil {
|
2021-03-24 14:12:35 +00:00
|
|
|
return xerrors.Errorf("creating message prototype: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:43:28 +00:00
|
|
|
sm, err := InteractiveSend(ctx, cctx, srv, proto)
|
2021-03-24 14:12:35 +00:00
|
|
|
if err != nil {
|
2022-09-01 14:30:36 +00:00
|
|
|
if strings.Contains(err.Error(), "no current EF") {
|
|
|
|
return xerrors.Errorf("transaction rejected on ledger: %w", err)
|
|
|
|
}
|
2022-09-01 15:01:03 +00:00
|
|
|
return err
|
2020-12-25 08:25:46 +00:00
|
|
|
}
|
|
|
|
|
2021-04-02 13:43:28 +00:00
|
|
|
fmt.Fprintf(cctx.App.Writer, "%s\n", sm.Cid())
|
2021-01-26 16:02:13 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|