2019-08-07 23:22:35 +00:00
package cli
import (
2023-02-24 18:04:57 +00:00
"bytes"
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"
2023-02-24 18:04:57 +00:00
cbg "github.com/whyrusleeping/cbor-gen"
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"
2023-02-24 18:04:57 +00:00
builtintypes "github.com/filecoin-project/go-state-types/builtin"
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"
2023-01-19 22:57:48 +00:00
"github.com/filecoin-project/lotus/chain/types/ethtypes"
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
} ,
2023-01-19 22:57:48 +00:00
& cli . StringFlag {
Name : "from-eth-addr" ,
Usage : "optionally specify the eth addr to send funds from" ,
} ,
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'" )
}
2022-09-14 18:33:29 +00:00
if cctx . NArg ( ) != 2 {
2022-09-14 19:38:15 +00:00
return IncorrectNumArgs ( cctx )
2020-07-23 19:31:28 +00:00
}
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
2023-01-19 22:57:48 +00:00
} else if from := cctx . String ( "from-eth-addr" ) ; from != "" {
eaddr , err := ethtypes . ParseEthAddress ( from )
if err != nil {
return err
}
faddr , err := eaddr . ToFilecoinAddress ( )
if err != nil {
fmt . Println ( "error on conversion to faddr" )
return err
}
fmt . Println ( "f4 addr: " , faddr )
params . From = faddr
2021-02-23 14:50:47 +00:00
}
2023-02-24 18:04:57 +00:00
if cctx . IsSet ( "params-hex" ) {
decparams , err := hex . DecodeString ( cctx . String ( "params-hex" ) )
if err != nil {
return fmt . Errorf ( "failed to decode hex params: %w" , err )
}
params . Params = decparams
}
if ethtypes . IsEthAddress ( params . From ) {
// Method numbers don't make sense from eth accounts.
if cctx . IsSet ( "method" ) {
return xerrors . Errorf ( "messages from f410f addresses may not specify a method number" )
}
// Now, figure out the correct method number from the recipient.
if params . To == builtintypes . EthereumAddressManagerActorAddr {
params . Method = builtintypes . MethodsEAM . CreateExternal
} else {
params . Method = builtintypes . MethodsEVM . InvokeContract
}
if cctx . IsSet ( "params-json" ) {
return xerrors . Errorf ( "may not call with json parameters from an eth account" )
}
// And format the parameters, if present.
if len ( params . Params ) > 0 {
var buf bytes . Buffer
if err := cbg . WriteByteArray ( & buf , params . Params ) ; err != nil {
return xerrors . Errorf ( "failed to marshal EVM parameters" )
}
params . Params = buf . Bytes ( )
}
// We can only send to an f410f or f0 address.
2023-02-01 16:27:46 +00:00
if ! ( params . To . Protocol ( ) == address . ID || params . To . Protocol ( ) == address . Delegated ) {
api := srv . FullNodeAPI ( )
// Resolve id addr if possible.
params . To , err = api . StateLookupID ( ctx , params . To , types . EmptyTSK )
if err != nil {
2023-02-24 18:04:57 +00:00
return xerrors . Errorf ( "addresses starting with f410f can only send to other addresses starting with f410f, or id addresses. could not find id address for %s" , params . To . String ( ) )
2023-02-01 16:27:46 +00:00
}
}
2023-02-24 18:04:57 +00:00
} else {
params . Method = abi . MethodNum ( cctx . Uint64 ( "method" ) )
2023-02-01 16:27:46 +00:00
}
2021-02-23 14:50:47 +00:00
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
2020-07-23 02:30:51 +00:00
if cctx . IsSet ( "params-json" ) {
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'" )
}
2023-02-24 18:04:57 +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 {
2023-02-24 18:04:57 +00:00
return fmt . Errorf ( "failed to decode json params: %w" , err )
2020-07-23 02:30:51 +00:00
}
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
} ,
}