package types import ( "math/big" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/tharsis/ethermint/types" ) func newDynamicFeeTx(tx *ethtypes.Transaction) *DynamicFeeTx { txData := &DynamicFeeTx{ Nonce: tx.Nonce(), Data: tx.Data(), GasLimit: tx.Gas(), } v, r, s := tx.RawSignatureValues() if tx.To() != nil { txData.To = tx.To().Hex() } if tx.Value() != nil { amountInt := sdk.NewIntFromBigInt(tx.Value()) txData.Amount = &amountInt } if tx.GasFeeCap() != nil { gasFeeCapInt := sdk.NewIntFromBigInt(tx.GasFeeCap()) txData.GasFeeCap = &gasFeeCapInt } if tx.GasTipCap() != nil { gasTipCapInt := sdk.NewIntFromBigInt(tx.GasTipCap()) txData.GasTipCap = &gasTipCapInt } if tx.AccessList() != nil { al := tx.AccessList() txData.Accesses = NewAccessList(&al) } txData.SetSignatureValues(tx.ChainId(), v, r, s) return txData } // TxType returns the tx type func (tx *DynamicFeeTx) TxType() uint8 { return ethtypes.DynamicFeeTxType } // Copy returns an instance with the same field values func (tx *DynamicFeeTx) Copy() TxData { return &DynamicFeeTx{ ChainID: tx.ChainID, Nonce: tx.Nonce, GasTipCap: tx.GasTipCap, GasFeeCap: tx.GasFeeCap, GasLimit: tx.GasLimit, To: tx.To, Amount: tx.Amount, Data: common.CopyBytes(tx.Data), Accesses: tx.Accesses, V: common.CopyBytes(tx.V), R: common.CopyBytes(tx.R), S: common.CopyBytes(tx.S), } } // GetChainID returns the chain id field from the DynamicFeeTx func (tx *DynamicFeeTx) GetChainID() *big.Int { if tx.ChainID == nil { return nil } return tx.ChainID.BigInt() } // GetAccessList returns the AccessList field. func (tx *DynamicFeeTx) GetAccessList() ethtypes.AccessList { if tx.Accesses == nil { return nil } return *tx.Accesses.ToEthAccessList() } // GetData returns the a copy of the input data bytes. func (tx *DynamicFeeTx) GetData() []byte { return common.CopyBytes(tx.Data) } // GetGas returns the gas limit. func (tx *DynamicFeeTx) GetGas() uint64 { return tx.GasLimit } // GetGasPrice returns the gas fee cap field. func (tx *DynamicFeeTx) GetGasPrice() *big.Int { return tx.GetGasFeeCap() } // GetGasTipCap returns the gas tip cap field. func (tx *DynamicFeeTx) GetGasTipCap() *big.Int { if tx.GasTipCap == nil { return nil } return tx.GasTipCap.BigInt() } // GetGasFeeCap returns the gas fee cap field. func (tx *DynamicFeeTx) GetGasFeeCap() *big.Int { if tx.GasFeeCap == nil { return nil } return tx.GasFeeCap.BigInt() } // GetValue returns the tx amount. func (tx *DynamicFeeTx) GetValue() *big.Int { if tx.Amount == nil { return nil } return tx.Amount.BigInt() } // GetNonce returns the account sequence for the transaction. func (tx *DynamicFeeTx) GetNonce() uint64 { return tx.Nonce } // GetTo returns the pointer to the recipient address. func (tx *DynamicFeeTx) GetTo() *common.Address { if tx.To == "" { return nil } to := common.HexToAddress(tx.To) return &to } // AsEthereumData returns an DynamicFeeTx transaction tx from the proto-formatted // TxData defined on the Cosmos EVM. func (tx *DynamicFeeTx) AsEthereumData() ethtypes.TxData { v, r, s := tx.GetRawSignatureValues() return ðtypes.DynamicFeeTx{ ChainID: tx.GetChainID(), Nonce: tx.GetNonce(), GasTipCap: tx.GetGasTipCap(), GasFeeCap: tx.GetGasFeeCap(), Gas: tx.GetGas(), To: tx.GetTo(), Value: tx.GetValue(), Data: tx.GetData(), AccessList: tx.GetAccessList(), V: v, R: r, S: s, } } // GetRawSignatureValues returns the V, R, S signature values of the transaction. // The return values should not be modified by the caller. func (tx *DynamicFeeTx) GetRawSignatureValues() (v, r, s *big.Int) { return rawSignatureValues(tx.V, tx.R, tx.S) } // SetSignatureValues sets the signature values to the transaction. func (tx *DynamicFeeTx) SetSignatureValues(chainID, v, r, s *big.Int) { if v != nil { tx.V = v.Bytes() } if r != nil { tx.R = r.Bytes() } if s != nil { tx.S = s.Bytes() } if chainID != nil { chainIDInt := sdk.NewIntFromBigInt(chainID) tx.ChainID = &chainIDInt } } // Validate performs a stateless validation of the tx fields. func (tx DynamicFeeTx) Validate() error { if tx.GasTipCap == nil { return sdkerrors.Wrap(ErrInvalidGasCap, "gas tip cap cannot nil") } if tx.GasFeeCap == nil { return sdkerrors.Wrap(ErrInvalidGasCap, "gas fee cap cannot nil") } if tx.GasTipCap.IsNegative() { return sdkerrors.Wrapf(ErrInvalidGasCap, "gas tip cap cannot be negative %s", tx.GasTipCap) } if tx.GasFeeCap.IsNegative() { return sdkerrors.Wrapf(ErrInvalidGasCap, "gas fee cap cannot be negative %s", tx.GasFeeCap) } if tx.GasFeeCap.LT(*tx.GasTipCap) { return sdkerrors.Wrapf( ErrInvalidGasCap, "max priority fee per gas higher than max fee per gas (%s > %s)", tx.GasTipCap, tx.GasFeeCap, ) } amount := tx.GetValue() // Amount can be 0 if amount != nil && amount.Sign() == -1 { return sdkerrors.Wrapf(ErrInvalidAmount, "amount cannot be negative %s", amount) } if tx.To != "" { if err := types.ValidateAddress(tx.To); err != nil { return sdkerrors.Wrap(err, "invalid to address") } } if tx.GetChainID() == nil { return sdkerrors.Wrap( sdkerrors.ErrInvalidChainID, "chain ID must be present on AccessList txs", ) } return nil } // Fee returns gasprice * gaslimit. func (tx DynamicFeeTx) Fee() *big.Int { return fee(tx.GetGasPrice(), tx.GasLimit) } // Cost returns amount + gasprice * gaslimit. func (tx DynamicFeeTx) Cost() *big.Int { return cost(tx.Fee(), tx.GetValue()) }