@@ -7,28 +7,57 @@ import (
77 "fmt"
88 "math/big"
99
10+ "github.com/ethereum/go-ethereum"
11+ "github.com/ethereum/go-ethereum/common"
12+
1013 "github.com/bcdevtools/devd/v2/cmd/utils"
1114 ethtypes "github.com/ethereum/go-ethereum/core/types"
1215 "github.com/spf13/cobra"
1316)
1417
18+ const flagErc20 = "erc20"
19+
1520func GetSendEvmTxCommand () * cobra.Command {
1621 cmd := & cobra.Command {
1722 Use : "send [to] [amount]" ,
18- Short : "Send some token to an address via EVM transfer " ,
23+ Short : "Send some native coin or ERC-20 token to an address" ,
1924 Args : cobra .ExactArgs (2 ),
2025 Run : func (cmd * cobra.Command , args []string ) {
2126 ethClient8545 , _ := mustGetEthClient (cmd )
2227
2328 evmAddrs , err := utils .GetEvmAddressFromAnyFormatAddress (args [0 ])
2429 utils .ExitOnErr (err , "failed to get evm address from input" )
2530
31+ var pErc20ContractAddress * common.Address
32+ erc20ContractAddress , _ := cmd .Flags ().GetString (flagErc20 )
33+ if erc20ContractAddress != "" {
34+ if ! common .IsHexAddress (erc20ContractAddress ) {
35+ utils .ExitOnErr (fmt .Errorf ("invalid format" ), "failed to parse ERC-20 contract address" )
36+ }
37+ contractAddr := common .HexToAddress (erc20ContractAddress )
38+ pErc20ContractAddress = & contractAddr
39+ }
40+
2641 receiverAddr := evmAddrs [0 ]
2742 amount , ok := new (big.Int ).SetString (args [1 ], 10 )
2843 if ! ok {
2944 utils .ExitOnErr (fmt .Errorf ("invalid amount %s" , args [1 ]), "failed to parse amount" )
3045 }
31- display , _ , _ , err := utils .ConvertNumberIntoDisplayWithExponent (amount , 18 )
46+
47+ var exponent int
48+ if pErc20ContractAddress != nil {
49+ bz , err := ethClient8545 .CallContract (context .Background (), ethereum.CallMsg {
50+ To : pErc20ContractAddress ,
51+ Data : []byte {0x31 , 0x3c , 0xe5 , 0x67 }, // decimals()
52+ }, nil )
53+ utils .ExitOnErr (err , "failed to get contract decimals" )
54+
55+ contractDecimals := new (big.Int ).SetBytes (bz )
56+ exponent = int (contractDecimals .Int64 ())
57+ } else {
58+ exponent = 18
59+ }
60+ display , _ , _ , err := utils .ConvertNumberIntoDisplayWithExponent (amount , exponent )
3261 utils .ExitOnErr (err , "failed to convert amount into display with exponent" )
3362
3463 _ , ecdsaPrivateKey , _ , from := mustSecretEvmAccount (cmd )
@@ -39,12 +68,28 @@ func GetSendEvmTxCommand() *cobra.Command {
3968 chainId , err := ethClient8545 .ChainID (context .Background ())
4069 utils .ExitOnErr (err , "failed to get chain ID" )
4170
42- txData := ethtypes.LegacyTx {
43- Nonce : nonce ,
44- GasPrice : big .NewInt (20_000_000_000 ),
45- Gas : 21000 ,
46- To : & receiverAddr ,
47- Value : amount ,
71+ var txData ethtypes.LegacyTx
72+ if pErc20ContractAddress != nil {
73+ data := []byte {0xa9 , 0x05 , 0x9c , 0xbb }
74+ data = append (data , common .LeftPadBytes (receiverAddr .Bytes (), 32 )... )
75+ data = append (data , common .LeftPadBytes (amount .Bytes (), 32 )... )
76+
77+ txData = ethtypes.LegacyTx {
78+ Nonce : nonce ,
79+ GasPrice : big .NewInt (20_000_000_000 ),
80+ Gas : 500_000 ,
81+ To : pErc20ContractAddress ,
82+ Value : big .NewInt (0 ),
83+ Data : data ,
84+ }
85+ } else {
86+ txData = ethtypes.LegacyTx {
87+ Nonce : nonce ,
88+ GasPrice : big .NewInt (20_000_000_000 ),
89+ Gas : 21000 ,
90+ To : & receiverAddr ,
91+ Value : amount ,
92+ }
4893 }
4994 tx := ethtypes .NewTx (& txData )
5095
@@ -68,6 +113,7 @@ func GetSendEvmTxCommand() *cobra.Command {
68113
69114 cmd .Flags ().String (flagRpc , "" , flagEvmRpcDesc )
70115 cmd .Flags ().String (flagSecretKey , "" , flagSecretKeyDesc )
116+ cmd .Flags ().String (flagErc20 , "" , "contract address if you want to send ERC-20 token instead of native coin" )
71117
72118 return cmd
73119}
0 commit comments