Skip to content

Commit 0855ecf

Browse files
authored
Merge pull request #6 from bcdevtools/imp/allow-send-erc20
imp: allow send ERC-20
2 parents 9f71d42 + 0de3d81 commit 0855ecf

File tree

1 file changed

+54
-8
lines changed

1 file changed

+54
-8
lines changed

cmd/tx/send.go

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
1520
func 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

Comments
 (0)