2018-11-28 22:19:22 +00:00
|
|
|
package types
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
2019-11-01 15:26:53 +00:00
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
2021-05-12 13:08:31 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
2018-11-28 22:19:22 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2020-04-16 15:47:39 +00:00
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
2021-05-31 09:05:32 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
2021-06-21 13:09:23 +00:00
|
|
|
|
2021-06-22 10:49:18 +00:00
|
|
|
"github.com/tharsis/ethermint/types"
|
2018-11-28 22:19:22 +00:00
|
|
|
|
2021-06-11 13:38:51 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2021-05-10 16:34:00 +00:00
|
|
|
"github.com/ethereum/go-ethereum/core"
|
2018-11-28 22:19:22 +00:00
|
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
|
|
)
|
|
|
|
|
2018-12-18 16:10:04 +00:00
|
|
|
var (
|
2021-05-31 09:05:32 +00:00
|
|
|
_ sdk.Msg = &MsgEthereumTx{}
|
|
|
|
_ sdk.Tx = &MsgEthereumTx{}
|
|
|
|
_ ante.GasTx = &MsgEthereumTx{}
|
2021-07-05 16:39:08 +00:00
|
|
|
|
|
|
|
_ codectypes.UnpackInterfacesMessage = MsgEthereumTx{}
|
2018-12-18 16:10:04 +00:00
|
|
|
)
|
|
|
|
|
2018-11-28 22:19:22 +00:00
|
|
|
// message type and route constants
|
|
|
|
const (
|
2021-05-05 13:10:21 +00:00
|
|
|
// TypeMsgEthereumTx defines the type string of an Ethereum transaction
|
2021-05-14 21:44:58 +00:00
|
|
|
TypeMsgEthereumTx = "ethereum_tx"
|
2018-11-28 22:19:22 +00:00
|
|
|
)
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
// NewTx returns a reference to a new Ethereum transaction message.
|
|
|
|
func NewTx(
|
2021-06-11 13:38:51 +00:00
|
|
|
chainID *big.Int, nonce uint64, to *common.Address, amount *big.Int,
|
2021-05-10 16:34:00 +00:00
|
|
|
gasLimit uint64, gasPrice *big.Int, input []byte, accesses *ethtypes.AccessList,
|
2021-04-17 10:00:07 +00:00
|
|
|
) *MsgEthereumTx {
|
2021-05-10 16:34:00 +00:00
|
|
|
return newMsgEthereumTx(chainID, nonce, to, amount, gasLimit, gasPrice, input, accesses)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
// NewTxContract returns a reference to a new Ethereum transaction
|
2018-11-28 22:19:22 +00:00
|
|
|
// message designated for contract creation.
|
2021-07-05 16:39:08 +00:00
|
|
|
func NewTxContract(
|
2021-05-10 16:34:00 +00:00
|
|
|
chainID *big.Int, nonce uint64, amount *big.Int,
|
|
|
|
gasLimit uint64, gasPrice *big.Int, input []byte, accesses *ethtypes.AccessList,
|
2021-04-17 10:00:07 +00:00
|
|
|
) *MsgEthereumTx {
|
2021-05-10 16:34:00 +00:00
|
|
|
return newMsgEthereumTx(chainID, nonce, nil, amount, gasLimit, gasPrice, input, accesses)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 18:49:21 +00:00
|
|
|
func newMsgEthereumTx(
|
2021-06-11 13:38:51 +00:00
|
|
|
chainID *big.Int, nonce uint64, to *common.Address, amount *big.Int,
|
2021-05-10 16:34:00 +00:00
|
|
|
gasLimit uint64, gasPrice *big.Int, input []byte, accesses *ethtypes.AccessList,
|
2021-04-17 10:00:07 +00:00
|
|
|
) *MsgEthereumTx {
|
2021-07-05 16:39:08 +00:00
|
|
|
var (
|
|
|
|
cid, amt, gp *sdk.Int
|
|
|
|
toAddr string
|
|
|
|
txData TxData
|
|
|
|
)
|
|
|
|
|
|
|
|
if to != nil {
|
|
|
|
toAddr = to.Hex()
|
|
|
|
}
|
2020-05-29 15:50:22 +00:00
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
if amount != nil {
|
|
|
|
amountInt := sdk.NewIntFromBigInt(amount)
|
|
|
|
amt = &amountInt
|
2021-06-01 17:14:33 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
if chainID != nil {
|
|
|
|
chainIDInt := sdk.NewIntFromBigInt(chainID)
|
|
|
|
cid = &chainIDInt
|
2021-06-11 13:38:51 +00:00
|
|
|
}
|
2021-07-05 16:39:08 +00:00
|
|
|
|
|
|
|
if gasPrice != nil {
|
|
|
|
gasPriceInt := sdk.NewIntFromBigInt(gasPrice)
|
|
|
|
gp = &gasPriceInt
|
2021-06-11 13:38:51 +00:00
|
|
|
}
|
2021-07-05 16:39:08 +00:00
|
|
|
|
|
|
|
if accesses == nil {
|
|
|
|
txData = &LegacyTx{
|
|
|
|
Nonce: nonce,
|
|
|
|
To: toAddr,
|
|
|
|
Amount: amt,
|
|
|
|
GasLimit: gasLimit,
|
|
|
|
GasPrice: gp,
|
|
|
|
Data: input,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
txData = &AccessListTx{
|
|
|
|
ChainID: cid,
|
|
|
|
Nonce: nonce,
|
|
|
|
To: toAddr,
|
|
|
|
Amount: amt,
|
|
|
|
GasLimit: gasLimit,
|
|
|
|
GasPrice: gp,
|
|
|
|
Data: input,
|
|
|
|
Accesses: NewAccessList(accesses),
|
|
|
|
}
|
2021-06-11 13:38:51 +00:00
|
|
|
}
|
2021-07-05 16:39:08 +00:00
|
|
|
|
|
|
|
dataAny, err := PackTxData(txData)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
2021-06-11 13:38:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
return &MsgEthereumTx{Data: dataAny}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fromEthereumTx populates the message fields from the given ethereum transaction
|
|
|
|
func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) {
|
|
|
|
txData := NewTxDataFromTx(tx)
|
|
|
|
|
|
|
|
anyTxData, err := PackTxData(txData)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2021-06-11 13:38:51 +00:00
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
msg.Data = anyTxData
|
2021-06-01 17:14:33 +00:00
|
|
|
msg.Size_ = float64(tx.Size())
|
2021-06-08 11:11:37 +00:00
|
|
|
msg.Hash = tx.Hash().Hex()
|
2021-06-01 17:14:33 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 18:49:21 +00:00
|
|
|
// Route returns the route value of an MsgEthereumTx.
|
|
|
|
func (msg MsgEthereumTx) Route() string { return RouterKey }
|
2018-11-28 22:19:22 +00:00
|
|
|
|
2020-04-01 18:49:21 +00:00
|
|
|
// Type returns the type value of an MsgEthereumTx.
|
|
|
|
func (msg MsgEthereumTx) Type() string { return TypeMsgEthereumTx }
|
2018-11-28 22:19:22 +00:00
|
|
|
|
|
|
|
// ValidateBasic implements the sdk.Msg interface. It performs basic validation
|
2020-04-01 18:49:21 +00:00
|
|
|
// checks of a Transaction. If returns an error if validation fails.
|
2020-04-22 19:26:01 +00:00
|
|
|
func (msg MsgEthereumTx) ValidateBasic() error {
|
2021-05-14 06:52:18 +00:00
|
|
|
if msg.From != "" {
|
|
|
|
if err := types.ValidateAddress(msg.From); err != nil {
|
|
|
|
return sdkerrors.Wrap(err, "invalid from address")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
txData, err := UnpackTxData(msg.Data)
|
|
|
|
if err != nil {
|
|
|
|
return sdkerrors.Wrap(err, "failed to unpack tx data")
|
|
|
|
}
|
2018-11-28 22:19:22 +00:00
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
return txData.Validate()
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 18:49:21 +00:00
|
|
|
// GetMsgs returns a single MsgEthereumTx as an sdk.Msg.
|
2021-04-17 10:00:07 +00:00
|
|
|
func (msg *MsgEthereumTx) GetMsgs() []sdk.Msg {
|
2018-12-18 16:10:04 +00:00
|
|
|
return []sdk.Msg{msg}
|
|
|
|
}
|
|
|
|
|
2018-11-28 22:19:22 +00:00
|
|
|
// GetSigners returns the expected signers for an Ethereum transaction message.
|
|
|
|
// For such a message, there should exist only a single 'signer'.
|
|
|
|
//
|
2021-05-31 09:05:32 +00:00
|
|
|
// NOTE: This method panics if 'Sign' hasn't been called first.
|
2021-07-05 16:39:08 +00:00
|
|
|
func (msg *MsgEthereumTx) GetSigners() []sdk.AccAddress {
|
|
|
|
data, err := UnpackTxData(msg.Data)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2021-05-31 09:05:32 +00:00
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
sender, err := msg.GetSender(data.GetChainID())
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
2020-04-17 22:32:01 +00:00
|
|
|
}
|
2021-05-10 16:34:00 +00:00
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
signer := sdk.AccAddress(sender.Bytes())
|
2021-05-10 16:34:00 +00:00
|
|
|
return []sdk.AccAddress{signer}
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetSignBytes returns the Amino bytes of an Ethereum transaction message used
|
|
|
|
// for signing.
|
|
|
|
//
|
|
|
|
// NOTE: This method cannot be used as a chain ID is needed to create valid bytes
|
|
|
|
// to sign over. Use 'RLPSignBytes' instead.
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg MsgEthereumTx) GetSignBytes() []byte {
|
2018-11-28 22:19:22 +00:00
|
|
|
panic("must use 'RLPSignBytes' with a chain ID to get the valid bytes to sign")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sign calculates a secp256k1 ECDSA signature and signs the transaction. It
|
2021-05-12 13:08:31 +00:00
|
|
|
// takes a keyring signer and the chainID to sign an Ethereum transaction according to
|
|
|
|
// EIP155 standard.
|
|
|
|
// This method mutates the transaction as it populates the V, R, S
|
2018-11-28 22:19:22 +00:00
|
|
|
// fields of the Transaction's Signature.
|
2021-05-12 13:08:31 +00:00
|
|
|
// The function will fail if the sender address is not defined for the msg or if
|
|
|
|
// the sender is not registered on the keyring
|
2021-06-01 17:14:33 +00:00
|
|
|
func (msg *MsgEthereumTx) Sign(ethSigner ethtypes.Signer, keyringSigner keyring.Signer) error {
|
2021-05-12 13:08:31 +00:00
|
|
|
from := msg.GetFrom()
|
2021-05-31 14:54:59 +00:00
|
|
|
if from.Empty() {
|
2021-05-12 13:08:31 +00:00
|
|
|
return fmt.Errorf("sender address not defined for message")
|
|
|
|
}
|
|
|
|
|
2021-06-01 17:14:33 +00:00
|
|
|
tx := msg.AsTransaction()
|
|
|
|
txHash := ethSigner.Hash(tx)
|
2018-11-28 22:19:22 +00:00
|
|
|
|
2021-06-01 17:14:33 +00:00
|
|
|
sig, _, err := keyringSigner.SignByAddress(from, txHash.Bytes())
|
2018-11-28 22:19:22 +00:00
|
|
|
if err != nil {
|
2020-04-23 15:49:25 +00:00
|
|
|
return err
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-01 17:14:33 +00:00
|
|
|
tx, err = tx.WithSignature(ethSigner, sig)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 08:06:12 +00:00
|
|
|
msg.FromEthereumTx(tx)
|
2020-04-23 15:49:25 +00:00
|
|
|
return nil
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2020-04-17 22:32:01 +00:00
|
|
|
// GetGas implements the GasTx interface. It returns the GasLimit of the transaction.
|
|
|
|
func (msg MsgEthereumTx) GetGas() uint64 {
|
2021-07-05 16:39:08 +00:00
|
|
|
txData, err := UnpackTxData(msg.Data)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
2021-06-14 12:42:34 +00:00
|
|
|
}
|
2021-07-05 16:39:08 +00:00
|
|
|
return txData.GetGas()
|
2020-04-23 15:49:25 +00:00
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// GetFrom loads the ethereum sender address from the sigcache and returns an
|
2020-04-17 22:32:01 +00:00
|
|
|
// sdk.AccAddress from its bytes
|
2021-04-17 10:00:07 +00:00
|
|
|
func (msg *MsgEthereumTx) GetFrom() sdk.AccAddress {
|
2021-05-10 16:34:00 +00:00
|
|
|
if msg.From == "" {
|
2020-04-17 22:32:01 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-06-11 13:38:51 +00:00
|
|
|
return common.HexToAddress(msg.From).Bytes()
|
2020-04-17 22:32:01 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 13:08:31 +00:00
|
|
|
// AsTransaction creates an Ethereum Transaction type from the msg fields
|
2021-05-10 16:34:00 +00:00
|
|
|
func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction {
|
2021-07-05 16:39:08 +00:00
|
|
|
txData, err := UnpackTxData(msg.Data)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return ethtypes.NewTx(txData.AsEthereumData())
|
2021-05-10 16:34:00 +00:00
|
|
|
}
|
|
|
|
|
2021-06-11 13:38:51 +00:00
|
|
|
// AsMessage creates an Ethereum core.Message from the msg fields
|
|
|
|
func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer) (core.Message, error) {
|
|
|
|
return msg.AsTransaction().AsMessage(signer)
|
2019-09-24 18:39:17 +00:00
|
|
|
}
|
2021-07-02 09:34:15 +00:00
|
|
|
|
|
|
|
// GetSender extracts the sender address from the signature values using the latest signer for the given chainID.
|
|
|
|
func (msg *MsgEthereumTx) GetSender(chainID *big.Int) (common.Address, error) {
|
|
|
|
signer := ethtypes.LatestSignerForChainID(chainID)
|
|
|
|
from, err := signer.Sender(msg.AsTransaction())
|
|
|
|
if err != nil {
|
|
|
|
return common.Address{}, err
|
|
|
|
}
|
2021-07-05 16:39:08 +00:00
|
|
|
|
2021-07-02 09:34:15 +00:00
|
|
|
msg.From = from.Hex()
|
|
|
|
return from, nil
|
|
|
|
}
|
2021-07-05 16:39:08 +00:00
|
|
|
|
|
|
|
// UnpackInterfaces implements UnpackInterfacesMesssage.UnpackInterfaces
|
|
|
|
func (msg MsgEthereumTx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
|
|
|
|
return unpacker.UnpackAny(msg.Data, new(TxData))
|
|
|
|
}
|