2018-11-28 22:19:22 +00:00
|
|
|
package types
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"math/big"
|
2019-11-01 15:26:53 +00:00
|
|
|
|
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-14 06:52:18 +00:00
|
|
|
"github.com/cosmos/ethermint/types"
|
2018-11-28 22:19:22 +00:00
|
|
|
|
|
|
|
ethcmn "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"
|
2021-05-12 13:08:31 +00:00
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2018-11-28 22:19:22 +00:00
|
|
|
"github.com/ethereum/go-ethereum/rlp"
|
|
|
|
)
|
|
|
|
|
2018-12-18 16:10:04 +00:00
|
|
|
var (
|
2021-04-17 10:00:07 +00:00
|
|
|
_ sdk.Msg = &MsgEthereumTx{}
|
|
|
|
_ sdk.Tx = &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
|
|
|
)
|
|
|
|
|
2020-04-01 18:49:21 +00:00
|
|
|
// NewMsgEthereumTx returns a reference to a new Ethereum transaction message.
|
|
|
|
func NewMsgEthereumTx(
|
2021-05-10 16:34:00 +00:00
|
|
|
chainID *big.Int, nonce uint64, to *ethcmn.Address, 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, to, amount, gasLimit, gasPrice, input, accesses)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 18:49:21 +00:00
|
|
|
// NewMsgEthereumTxContract returns a reference to a new Ethereum transaction
|
2018-11-28 22:19:22 +00:00
|
|
|
// message designated for contract creation.
|
2020-04-01 18:49:21 +00:00
|
|
|
func NewMsgEthereumTxContract(
|
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-05-10 16:34:00 +00:00
|
|
|
chainID *big.Int, nonce uint64, to *ethcmn.Address, 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
|
|
|
if len(input) > 0 {
|
|
|
|
input = ethcmn.CopyBytes(input)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 06:52:18 +00:00
|
|
|
var toHex string
|
2021-01-06 20:56:40 +00:00
|
|
|
if to != nil {
|
2021-05-14 06:52:18 +00:00
|
|
|
toHex = to.Hex()
|
2021-01-06 20:56:40 +00:00
|
|
|
}
|
|
|
|
|
2021-05-10 16:34:00 +00:00
|
|
|
var chainIDBz []byte
|
|
|
|
if chainID != nil {
|
|
|
|
chainIDBz = chainID.Bytes()
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
txData := &TxData{
|
2021-05-10 16:34:00 +00:00
|
|
|
ChainID: chainIDBz,
|
|
|
|
Nonce: nonce,
|
2021-05-14 06:52:18 +00:00
|
|
|
To: toHex,
|
2021-05-10 16:34:00 +00:00
|
|
|
Input: input,
|
|
|
|
GasLimit: gasLimit,
|
|
|
|
Amount: []byte{},
|
|
|
|
GasPrice: []byte{},
|
|
|
|
Accesses: NewAccessList(accesses),
|
|
|
|
V: []byte{},
|
|
|
|
R: []byte{},
|
|
|
|
S: []byte{},
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if amount != nil {
|
2021-04-18 15:54:18 +00:00
|
|
|
txData.Amount = amount.Bytes()
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
if gasPrice != nil {
|
2021-05-10 16:34:00 +00:00
|
|
|
txData.GasPrice = gasPrice.Bytes()
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
return &MsgEthereumTx{Data: txData}
|
2020-05-29 15:50:22 +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-10 16:34:00 +00:00
|
|
|
gasPrice := new(big.Int).SetBytes(msg.Data.GasPrice)
|
2021-04-18 15:54:18 +00:00
|
|
|
if gasPrice.Sign() == -1 {
|
|
|
|
return sdkerrors.Wrapf(ErrInvalidValue, "gas price cannot be negative %s", gasPrice)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2019-09-18 20:14:39 +00:00
|
|
|
// Amount can be 0
|
2021-04-18 15:54:18 +00:00
|
|
|
amount := new(big.Int).SetBytes(msg.Data.Amount)
|
|
|
|
if amount.Sign() == -1 {
|
|
|
|
return sdkerrors.Wrapf(ErrInvalidValue, "amount cannot be negative %s", amount)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 06:52:18 +00:00
|
|
|
if msg.Data.To != "" {
|
|
|
|
if err := types.ValidateAddress(msg.Data.To); err != nil {
|
|
|
|
return sdkerrors.Wrap(err, "invalid to address")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.From != "" {
|
|
|
|
if err := types.ValidateAddress(msg.From); err != nil {
|
|
|
|
return sdkerrors.Wrap(err, "invalid from address")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-28 22:19:22 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-12-18 16:10:04 +00:00
|
|
|
// To returns the recipient address of the transaction. It returns nil if the
|
|
|
|
// transaction is a contract creation.
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg MsgEthereumTx) To() *ethcmn.Address {
|
2021-05-14 06:52:18 +00:00
|
|
|
if msg.Data.To == "" {
|
2021-01-06 20:56:40 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-14 06:52:18 +00:00
|
|
|
recipient := ethcmn.HexToAddress(msg.Data.To)
|
2021-01-06 20:56:40 +00:00
|
|
|
return &recipient
|
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'.
|
|
|
|
//
|
2020-04-17 22:32:01 +00:00
|
|
|
// NOTE: This method panics if 'VerifySig' hasn't been called first.
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg MsgEthereumTx) GetSigners() []sdk.AccAddress {
|
2021-05-17 10:13:08 +00:00
|
|
|
if msg.From == "" {
|
2020-04-17 22:32:01 +00:00
|
|
|
panic("must use 'VerifySig' with a chain ID to get the signer")
|
|
|
|
}
|
2021-05-10 16:34:00 +00:00
|
|
|
|
|
|
|
signer := sdk.AccAddress(ethcmn.HexToAddress(msg.From).Bytes())
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
|
|
|
// RLPSignBytes returns the RLP hash of an Ethereum transaction message with a
|
|
|
|
// given chainID used for signing.
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg MsgEthereumTx) RLPSignBytes(chainID *big.Int) ethcmn.Hash {
|
2021-05-12 13:08:31 +00:00
|
|
|
if msg.Data.ChainID != nil {
|
|
|
|
chainID = new(big.Int).SetBytes(msg.Data.ChainID)
|
|
|
|
}
|
|
|
|
|
2021-05-10 16:34:00 +00:00
|
|
|
var accessList *ethtypes.AccessList
|
|
|
|
if msg.Data.Accesses != nil {
|
|
|
|
accessList = msg.Data.Accesses.ToEthAccessList()
|
|
|
|
}
|
|
|
|
|
2018-11-28 22:19:22 +00:00
|
|
|
return rlpHash([]interface{}{
|
2021-05-12 13:08:31 +00:00
|
|
|
chainID,
|
2021-05-10 16:34:00 +00:00
|
|
|
msg.Data.Nonce,
|
|
|
|
new(big.Int).SetBytes(msg.Data.GasPrice),
|
2018-11-28 22:19:22 +00:00
|
|
|
msg.Data.GasLimit,
|
2021-01-06 20:56:40 +00:00
|
|
|
msg.To(),
|
2021-04-18 15:54:18 +00:00
|
|
|
new(big.Int).SetBytes(msg.Data.Amount),
|
2021-05-10 16:34:00 +00:00
|
|
|
new(big.Int).SetBytes(msg.Data.Input),
|
|
|
|
accessList,
|
2018-11-28 22:19:22 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// EncodeRLP implements the rlp.Encoder interface.
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg *MsgEthereumTx) EncodeRLP(w io.Writer) error {
|
2021-04-18 15:54:18 +00:00
|
|
|
return rlp.Encode(w, &msg.Data)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DecodeRLP implements the rlp.Decoder interface.
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg *MsgEthereumTx) DecodeRLP(s *rlp.Stream) error {
|
2020-04-23 15:49:25 +00:00
|
|
|
_, size, err := s.Kind()
|
|
|
|
if err != nil {
|
|
|
|
// return error if stream is too large
|
|
|
|
return err
|
|
|
|
}
|
2018-11-28 22:19:22 +00:00
|
|
|
|
2021-04-18 15:54:18 +00:00
|
|
|
if err := s.Decode(&msg.Data); err != nil {
|
2020-04-23 15:49:25 +00:00
|
|
|
return err
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
msg.Size_ = float64(ethcmn.StorageSize(rlp.ListSize(size)))
|
2020-04-23 15:49:25 +00:00
|
|
|
return nil
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
func (msg *MsgEthereumTx) Sign(chainID *big.Int, signer keyring.Signer) error {
|
|
|
|
from := msg.GetFrom()
|
|
|
|
if from == nil {
|
|
|
|
return fmt.Errorf("sender address not defined for message")
|
|
|
|
}
|
|
|
|
|
2018-11-28 22:19:22 +00:00
|
|
|
txHash := msg.RLPSignBytes(chainID)
|
|
|
|
|
2021-05-12 13:08:31 +00:00
|
|
|
sig, _, err := signer.SignByAddress(from, txHash[:])
|
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-05-12 13:08:31 +00:00
|
|
|
if len(sig) != crypto.SignatureLength {
|
|
|
|
return fmt.Errorf(
|
|
|
|
"wrong size for signature: got %d, want %d",
|
|
|
|
len(sig),
|
|
|
|
crypto.SignatureLength,
|
|
|
|
)
|
2018-11-28 22:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r := new(big.Int).SetBytes(sig[:32])
|
|
|
|
s := new(big.Int).SetBytes(sig[32:64])
|
|
|
|
|
|
|
|
var v *big.Int
|
|
|
|
|
|
|
|
if chainID.Sign() == 0 {
|
|
|
|
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
|
|
|
|
} else {
|
|
|
|
v = big.NewInt(int64(sig[64] + 35))
|
|
|
|
chainIDMul := new(big.Int).Mul(chainID, big.NewInt(2))
|
|
|
|
|
|
|
|
v.Add(v, chainIDMul)
|
|
|
|
}
|
|
|
|
|
2021-01-06 20:56:40 +00:00
|
|
|
msg.Data.V = v.Bytes()
|
|
|
|
msg.Data.R = r.Bytes()
|
|
|
|
msg.Data.S = s.Bytes()
|
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 {
|
|
|
|
return msg.Data.GasLimit
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fee returns gasprice * gaslimit.
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg MsgEthereumTx) Fee() *big.Int {
|
2021-05-10 16:34:00 +00:00
|
|
|
gasPrice := new(big.Int).SetBytes(msg.Data.GasPrice)
|
2021-01-06 20:56:40 +00:00
|
|
|
gasLimit := new(big.Int).SetUint64(msg.Data.GasLimit)
|
|
|
|
return new(big.Int).Mul(gasPrice, gasLimit)
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
2019-09-24 18:39:17 +00:00
|
|
|
// ChainID returns which chain id this transaction was signed for (if at all)
|
2020-04-01 18:49:21 +00:00
|
|
|
func (msg *MsgEthereumTx) ChainID() *big.Int {
|
2021-05-10 16:34:00 +00:00
|
|
|
return new(big.Int).SetBytes(msg.Data.ChainID)
|
2019-09-24 18:39:17 +00:00
|
|
|
}
|
|
|
|
|
2020-04-17 22:32:01 +00:00
|
|
|
// Cost returns amount + gasprice * gaslimit.
|
|
|
|
func (msg MsgEthereumTx) Cost() *big.Int {
|
|
|
|
total := msg.Fee()
|
2021-04-18 15:54:18 +00:00
|
|
|
total.Add(total, new(big.Int).SetBytes(msg.Data.Amount))
|
2020-04-17 22:32:01 +00:00
|
|
|
return total
|
|
|
|
}
|
|
|
|
|
2020-04-23 15:49:25 +00:00
|
|
|
// RawSignatureValues returns the V, R, S signature values of the transaction.
|
|
|
|
// The return values should not be modified by the caller.
|
|
|
|
func (msg MsgEthereumTx) RawSignatureValues() (v, r, s *big.Int) {
|
2021-01-06 20:56:40 +00:00
|
|
|
return new(big.Int).SetBytes(msg.Data.V),
|
|
|
|
new(big.Int).SetBytes(msg.Data.R),
|
|
|
|
new(big.Int).SetBytes(msg.Data.S)
|
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-05-10 16:34:00 +00:00
|
|
|
return ethcmn.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 {
|
|
|
|
return ethtypes.NewTx(msg.Data.AsEthereumData())
|
|
|
|
}
|
|
|
|
|
2021-05-12 13:08:31 +00:00
|
|
|
// AsMessage creates an Ethereum core.Message from the msg fields. This method
|
|
|
|
// fails if the sender address is not defined
|
2021-05-10 16:34:00 +00:00
|
|
|
func (msg MsgEthereumTx) AsMessage() (core.Message, error) {
|
|
|
|
if msg.From == "" {
|
|
|
|
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "'from' address cannot be empty")
|
|
|
|
}
|
|
|
|
|
|
|
|
from := ethcmn.HexToAddress(msg.From)
|
|
|
|
|
|
|
|
var to *ethcmn.Address
|
2021-05-14 06:52:18 +00:00
|
|
|
if msg.Data.To != "" {
|
|
|
|
toAddr := ethcmn.HexToAddress(msg.Data.To)
|
2021-05-10 16:34:00 +00:00
|
|
|
to = &toAddr
|
|
|
|
}
|
|
|
|
|
|
|
|
var accessList ethtypes.AccessList
|
|
|
|
if msg.Data.Accesses != nil {
|
|
|
|
accessList = *msg.Data.Accesses.ToEthAccessList()
|
|
|
|
}
|
|
|
|
|
|
|
|
return ethtypes.NewMessage(
|
|
|
|
from,
|
|
|
|
to,
|
|
|
|
msg.Data.Nonce,
|
|
|
|
new(big.Int).SetBytes(msg.Data.Amount),
|
|
|
|
msg.Data.GasLimit,
|
|
|
|
new(big.Int).SetBytes(msg.Data.GasPrice),
|
|
|
|
msg.Data.Input,
|
|
|
|
accessList,
|
|
|
|
true,
|
|
|
|
), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AsEthereumData returns an AccessListTx transaction data from the proto-formatted
|
|
|
|
// TxData defined on the Cosmos EVM.
|
|
|
|
func (data TxData) AsEthereumData() ethtypes.TxData {
|
|
|
|
var to *ethcmn.Address
|
2021-05-14 06:52:18 +00:00
|
|
|
if data.To != "" {
|
|
|
|
toAddr := ethcmn.HexToAddress(data.To)
|
2021-05-10 16:34:00 +00:00
|
|
|
to = &toAddr
|
|
|
|
}
|
|
|
|
|
|
|
|
var accessList ethtypes.AccessList
|
|
|
|
if data.Accesses != nil {
|
|
|
|
accessList = *data.Accesses.ToEthAccessList()
|
|
|
|
}
|
|
|
|
|
|
|
|
return ðtypes.AccessListTx{
|
|
|
|
ChainID: new(big.Int).SetBytes(data.ChainID),
|
|
|
|
Nonce: data.Nonce,
|
|
|
|
GasPrice: new(big.Int).SetBytes(data.GasPrice),
|
|
|
|
Gas: data.GasLimit,
|
|
|
|
To: to,
|
|
|
|
Value: new(big.Int).SetBytes(data.Amount),
|
|
|
|
Data: data.Input,
|
|
|
|
AccessList: accessList,
|
|
|
|
V: new(big.Int).SetBytes(data.V),
|
|
|
|
R: new(big.Int).SetBytes(data.R),
|
|
|
|
S: new(big.Int).SetBytes(data.S),
|
2019-09-24 18:39:17 +00:00
|
|
|
}
|
|
|
|
}
|