-
Notifications
You must be signed in to change notification settings - Fork 0
/
evm.go
138 lines (116 loc) · 3.92 KB
/
evm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package cli
import (
"context"
"encoding/json"
"fmt"
"math/big"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/evmos/ethermint/crypto/hd"
"github.com/evmos/ethermint/server/config"
etherminttypes "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
)
// CanSignEthTx returns an error if the signing key algorithm is not eth_secp256k1.
func CanSignEthTx(ctx client.Context) error {
keyInfo, err := ctx.Keyring.KeyByAddress(ctx.FromAddress)
if err != nil {
return err
}
pubKey, err := keyInfo.GetPubKey()
if err != nil {
return err
}
if pubKey.Type() != string(hd.EthSecp256k1Type) {
return fmt.Errorf(
"invalid from address pubkey type, expected %s but got %s",
hd.EthSecp256k1Type,
pubKey.Type(),
)
}
return nil
}
// PackContractCallData creates a smart contract method call data with the
// provided method and args.
func PackContractCallData(abi abi.ABI, method string, args ...interface{}) ([]byte, error) {
data, err := abi.Pack(method, args...)
if err != nil {
return nil, fmt.Errorf("failed to create transaction data: %w", err)
}
return data, nil
}
// CreateEthCallContractTx creates and signs a Eth transaction wrapped in a
// cosmos Tx.
func CreateEthCallContractTx(
ctx client.Context,
contractAddr *common.Address,
data []byte,
) (signing.Tx, error) {
evmQueryClient := evmtypes.NewQueryClient(ctx)
feemarketQueryClient := feemarkettypes.NewQueryClient(ctx)
chainID, err := etherminttypes.ParseChainID(ctx.ChainID)
if err != nil {
return nil, fmt.Errorf("failed to parse chain ID: %w", err)
}
evmParamsRes, err := evmQueryClient.Params(context.Background(), &evmtypes.QueryParamsRequest{})
if err != nil {
return nil, fmt.Errorf("failed to fetch evm params: %w", err)
}
// Estimate Gas
from := common.BytesToAddress(ctx.FromAddress.Bytes())
transactionArgs := evmtypes.TransactionArgs{
From: &from,
To: contractAddr,
Data: (*hexutil.Bytes)(&data),
}
args, err := json.Marshal(transactionArgs)
if err != nil {
return nil, fmt.Errorf("failed to marshal transaction args for gas estimate: %w", err)
}
res, err := evmQueryClient.EstimateGas(context.Background(), &evmtypes.EthCallRequest{
Args: args,
GasCap: config.DefaultGasCap,
})
if err != nil {
return nil, fmt.Errorf("failed to estimate gas from EVM: %w", err)
}
// Fetch base fee
basefeeRes, err := feemarketQueryClient.BaseFee(
context.Background(),
&feemarkettypes.QueryBaseFeeRequest{},
)
if err != nil {
return nil, fmt.Errorf("failed to fetch basefee from feemarket: %w", err)
}
// Fetch account nonce, ignore error to use use 0 nonce if first tx
_, accSeq, _ := ctx.AccountRetriever.GetAccountNumberSequence(ctx, ctx.FromAddress)
// Create MsgEthereumTx
ethTx := evmtypes.NewTx(
chainID,
accSeq, // nonce
contractAddr, // to
nil, // amount
res.Gas, // gasLimit
nil, // gasPrice
basefeeRes.BaseFee.BigInt(), // gasFeeCap
big.NewInt(1), // gasTipCap
data, // input
ðtypes.AccessList{},
)
// Must set from address before signing
ethTx.From = from.String()
// Sign Ethereum TX (not the cosmos Msg)
signer := ethtypes.LatestSignerForChainID(chainID)
// Must sign with a `/ethermint.crypto.v1.ethsecp256k1.PubKey` and not
// `/cosmos.crypto.secp256k1.PubKey` or this will panic with the following:
// panic: wrong size for signature: got 64, want 65
if err := ethTx.Sign(signer, ctx.Keyring); err != nil {
return nil, err
}
return ethTx.BuildTx(ctx.TxConfig.NewTxBuilder(), evmParamsRes.Params.EvmDenom)
}