diff --git a/app/ante/evm_checktx_test.go b/app/ante/evm_checktx_test.go new file mode 100644 index 0000000000..58319b550f --- /dev/null +++ b/app/ante/evm_checktx_test.go @@ -0,0 +1,53 @@ +package ante + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +type evmStatelessCheckTx struct { + msgs []sdk.Msg +} + +func (tx evmStatelessCheckTx) GetMsgs() []sdk.Msg { + return tx.msgs +} + +func (tx evmStatelessCheckTx) ValidateBasic() error { + return nil +} + +func (tx evmStatelessCheckTx) GetGasEstimate() uint64 { + return 0 +} + +func TestEvmStatelessChecksRejectsEmptySetCodeAuthList(t *testing.T) { + chainID := sdk.NewInt(1) + gasTipCap := sdk.NewInt(50) + gasFeeCap := sdk.NewInt(100) + amount := sdk.NewInt(20) + setCodeTx := ðtx.SetCodeTx{ + ChainID: &chainID, + Nonce: 1, + GasTipCap: &gasTipCap, + GasFeeCap: &gasFeeCap, + GasLimit: 1000, + To: common.Address{'a'}.Hex(), + Amount: &amount, + AuthList: ethtx.AuthList{}, + V: []byte{3}, + R: []byte{5}, + S: []byte{7}, + } + msg, err := evmtypes.NewMsgEVMTransaction(setCodeTx) + require.NoError(t, err) + + err = EvmStatelessChecks(sdk.Context{}, evmStatelessCheckTx{msgs: []sdk.Msg{msg}}, big.NewInt(1)) + require.ErrorContains(t, err, "auth list cannot be empty") +} diff --git a/giga/deps/xevm/types/ethtx/semantic_validation.go b/giga/deps/xevm/types/ethtx/semantic_validation.go index 4da1422952..009e0371b6 100644 --- a/giga/deps/xevm/types/ethtx/semantic_validation.go +++ b/giga/deps/xevm/types/ethtx/semantic_validation.go @@ -48,6 +48,9 @@ func validateAccessList(accessList AccessList) error { } func validateAuthList(authList AuthList) error { + if len(authList) == 0 { + return fmt.Errorf("auth list cannot be empty") + } for _, auth := range authList { if auth.ChainID == nil { return fmt.Errorf("auth list chain id cannot be nil") diff --git a/x/evm/types/ethtx/semantic_validation.go b/x/evm/types/ethtx/semantic_validation.go index 4da1422952..009e0371b6 100644 --- a/x/evm/types/ethtx/semantic_validation.go +++ b/x/evm/types/ethtx/semantic_validation.go @@ -48,6 +48,9 @@ func validateAccessList(accessList AccessList) error { } func validateAuthList(authList AuthList) error { + if len(authList) == 0 { + return fmt.Errorf("auth list cannot be empty") + } for _, auth := range authList { if auth.ChainID == nil { return fmt.Errorf("auth list chain id cannot be nil") diff --git a/x/evm/types/ethtx/set_code_tx_test.go b/x/evm/types/ethtx/set_code_tx_test.go new file mode 100644 index 0000000000..12e052b0dd --- /dev/null +++ b/x/evm/types/ethtx/set_code_tx_test.go @@ -0,0 +1,75 @@ +package ethtx + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" + "github.com/stretchr/testify/require" +) + +func mockSetCodeTx(authList AuthList) *SetCodeTx { + chainID := sdk.NewInt(1) + gasTipCap := sdk.NewInt(50) + gasFeeCap := sdk.NewInt(100) + amount := sdk.NewInt(20) + ethAccessList := mockAccessList() + + return &SetCodeTx{ + ChainID: &chainID, + Nonce: 1, + GasTipCap: &gasTipCap, + GasFeeCap: &gasFeeCap, + GasLimit: 1000, + To: common.Address{'a'}.Hex(), + Amount: &amount, + Data: []byte{'b'}, + Accesses: NewAccessList(ðAccessList), + AuthList: authList, + V: []byte{3}, + R: []byte{5}, + S: []byte{7}, + } +} + +func mockAuthList() AuthList { + chainID := sdk.NewInt(1) + return AuthList{ + { + ChainID: &chainID, + Address: common.Address{'c'}.Hex(), + Nonce: 1, + V: []byte{0}, + R: []byte{5}, + S: []byte{7}, + }, + } +} + +func TestSetCodeTransaction(t *testing.T) { + tx := mockSetCodeTx(mockAuthList()) + require.NoError(t, tx.Validate()) + require.Equal(t, uint8(ethtypes.SetCodeTxType), tx.TxType()) + require.Equal(t, tx, tx.Copy()) + require.Equal(t, tx.GetAuthList(), ethtypes.NewTx(tx.AsEthereumData()).SetCodeAuthorizations()) + require.Nil(t, tx.GetBlobFeeCap()) + require.Nil(t, tx.GetBlobHashes()) + + baseFee := big.NewInt(2) + require.Equal(t, EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.EffectiveGasPrice(baseFee)) + require.Equal(t, fee(EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.GasLimit), tx.EffectiveFee(baseFee)) + require.Equal(t, cost(fee(EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.GasLimit), tx.Amount.BigInt()), tx.EffectiveCost(baseFee)) +} + +func TestValidateSetCodeTransactionRejectsEmptyAuthList(t *testing.T) { + tx := mockSetCodeTx(nil) + require.ErrorContains(t, tx.Validate(), "auth list cannot be empty") + + tx.AuthList = AuthList{} + require.ErrorContains(t, tx.Validate(), "auth list cannot be empty") + + tx.AuthList = mockAuthList() + require.NoError(t, tx.Validate()) +}