diff --git a/app/ante.go b/app/ante.go index 0a18887b4..0f8282d29 100644 --- a/app/ante.go +++ b/app/ante.go @@ -10,6 +10,7 @@ import ( authante "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/NibiruChain/nibiru/app/ante" + "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" devgasante "github.com/NibiruChain/nibiru/x/devgas/v1/ante" "github.com/NibiruChain/nibiru/x/evm" @@ -53,7 +54,7 @@ func AnteHandlerExtendedTx( ) (anteHandler sdk.AnteHandler) { switch typeUrl { case evm.TYPE_URL_ETHEREUM_TX: - anteHandler = NewAnteHandlerEVM(keepers, opts) + anteHandler = evmante.NewAnteHandlerEVM(opts) case eth.TYPE_URL_DYNAMIC_FEE_TX: anteHandler = NewAnteHandlerNonEVM(opts) default: @@ -73,7 +74,7 @@ func NewAnteHandlerNonEVM( opts ante.AnteHandlerOptions, ) sdk.AnteHandler { return sdk.ChainAnteDecorators( - AnteDecoratorPreventEtheruemTxMsgs{}, // reject MsgEthereumTxs + ante.AnteDecoratorPreventEtheruemTxMsgs{}, // reject MsgEthereumTxs authante.NewSetUpContextDecorator(), wasmkeeper.NewLimitSimulationGasDecorator(opts.WasmConfig.SimulationGasLimit), wasmkeeper.NewCountTXDecorator(opts.TxCounterStoreKey), @@ -103,7 +104,7 @@ func NewAnteHandlerNonEVM( authante.NewSigVerificationDecorator(opts.AccountKeeper, opts.SignModeHandler), authante.NewIncrementSequenceDecorator(opts.AccountKeeper), ibcante.NewRedundantRelayDecorator(opts.IBCKeeper), - AnteDecoratorGasWanted{}, + ante.AnteDecoratorGasWanted{}, ) } diff --git a/app/evmante_gas_wanted.go b/app/ante/gas_wanted.go similarity index 98% rename from app/evmante_gas_wanted.go rename to app/ante/gas_wanted.go index b7cebbfa3..1ef4e9752 100644 --- a/app/evmante_gas_wanted.go +++ b/app/ante/gas_wanted.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package ante import ( "cosmossdk.io/errors" diff --git a/app/evmante_gas_wanted_test.go b/app/ante/gas_wanted_test.go similarity index 82% rename from app/evmante_gas_wanted_test.go rename to app/ante/gas_wanted_test.go index f77531427..84a67e04e 100644 --- a/app/evmante_gas_wanted_test.go +++ b/app/ante/gas_wanted_test.go @@ -1,15 +1,16 @@ -package app_test +package ante_test import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/ante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" ) -func (s *TestSuite) TestGasWantedDecorator() { +func (s *AnteTestSuite) TestGasWantedDecorator() { testCases := []struct { name string ctxSetup func(deps *evmtest.TestDeps) @@ -19,7 +20,7 @@ func (s *TestSuite) TestGasWantedDecorator() { { name: "happy: non fee tx type", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - return happyCreateContractTx(deps) + return evmtestutil.HappyCreateContractTx(deps) }, wantErr: "", }, @@ -34,7 +35,7 @@ func (s *TestSuite) TestGasWantedDecorator() { txSetup: func(deps *evmtest.TestDeps) sdk.Tx { return legacytx.StdTx{ Msgs: []sdk.Msg{ - happyCreateContractTx(deps), + evmtestutil.HappyCreateContractTx(deps), }, } }, @@ -51,7 +52,7 @@ func (s *TestSuite) TestGasWantedDecorator() { txSetup: func(deps *evmtest.TestDeps) sdk.Tx { return legacytx.StdTx{ Msgs: []sdk.Msg{ - happyCreateContractTx(deps), + evmtestutil.HappyCreateContractTx(deps), }, Fee: legacytx.StdFee{Gas: 500}, } @@ -71,7 +72,7 @@ func (s *TestSuite) TestGasWantedDecorator() { txSetup: func(deps *evmtest.TestDeps) sdk.Tx { return legacytx.StdTx{ Msgs: []sdk.Msg{ - happyCreateContractTx(deps), + evmtestutil.HappyCreateContractTx(deps), }, Fee: legacytx.StdFee{Gas: 1000}, } @@ -84,7 +85,7 @@ func (s *TestSuite) TestGasWantedDecorator() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.AnteDecoratorGasWanted{} + anteDec := ante.AnteDecoratorGasWanted{} tx := tc.txSetup(&deps) s.Require().NoError(stateDB.Commit()) @@ -94,7 +95,7 @@ func (s *TestSuite) TestGasWantedDecorator() { tc.ctxSetup(&deps) } _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/ante/handler_opts.go b/app/ante/handler_opts.go index 79c099a00..2a9cd2408 100644 --- a/app/ante/handler_opts.go +++ b/app/ante/handler_opts.go @@ -7,10 +7,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/errors" sdkante "github.com/cosmos/cosmos-sdk/x/auth/ante" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" devgasante "github.com/NibiruChain/nibiru/x/devgas/v1/ante" devgaskeeper "github.com/NibiruChain/nibiru/x/devgas/v1/keeper" + evmkeeper "github.com/NibiruChain/nibiru/x/evm/keeper" ) type AnteHandlerOptions struct { @@ -18,6 +20,8 @@ type AnteHandlerOptions struct { IBCKeeper *ibckeeper.Keeper DevGasKeeper *devgaskeeper.Keeper DevGasBankKeeper devgasante.BankKeeper + EvmKeeper evmkeeper.Keeper + AccountKeeper authkeeper.AccountKeeper TxCounterStoreKey types.StoreKey WasmConfig *wasmtypes.WasmConfig @@ -25,9 +29,6 @@ type AnteHandlerOptions struct { } func (opts *AnteHandlerOptions) ValidateAndClean() error { - if opts.AccountKeeper == nil { - return AnteHandlerError("account keeper") - } if opts.BankKeeper == nil { return AnteHandlerError("bank keeper") } diff --git a/app/evmante_reject_msgs.go b/app/ante/reject_ethereum_tx_msgs.go similarity index 98% rename from app/evmante_reject_msgs.go rename to app/ante/reject_ethereum_tx_msgs.go index b9b1bb2ee..fb8f4d39d 100644 --- a/app/evmante_reject_msgs.go +++ b/app/ante/reject_ethereum_tx_msgs.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package ante import ( "cosmossdk.io/errors" diff --git a/app/evmante_reject_msgs_test.go b/app/ante/reject_ethereum_tx_msgs_test.go similarity index 63% rename from app/evmante_reject_msgs_test.go rename to app/ante/reject_ethereum_tx_msgs_test.go index 76636340f..147e4a0c8 100644 --- a/app/evmante_reject_msgs_test.go +++ b/app/ante/reject_ethereum_tx_msgs_test.go @@ -1,13 +1,14 @@ -package app_test +package ante_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/ante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" ) -func (s *TestSuite) TestAnteDecoratorPreventEtheruemTxMsgs() { +func (s *AnteTestSuite) TestAnteDecoratorPreventEtheruemTxMsgs() { testCases := []struct { name string txSetup func(deps *evmtest.TestDeps) sdk.Tx @@ -16,13 +17,13 @@ func (s *TestSuite) TestAnteDecoratorPreventEtheruemTxMsgs() { { name: "sad: evm message", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - return happyTransfertTx(deps, 0) + return evmtestutil.HappyTransferTx(deps, 0) }, wantErr: "invalid type", }, { name: "happy: non evm message", - txSetup: nonEvmMsgTx, + txSetup: evmtestutil.NonEvmMsgTx, wantErr: "", }, } @@ -30,11 +31,11 @@ func (s *TestSuite) TestAnteDecoratorPreventEtheruemTxMsgs() { for _, tc := range testCases { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() - anteDec := app.AnteDecoratorPreventEtheruemTxMsgs{} + anteDec := ante.AnteDecoratorPreventEtheruemTxMsgs{} tx := tc.txSetup(&deps) _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/app.go b/app/app.go index 60ba12494..9e6604ae6 100644 --- a/app/app.go +++ b/app/app.go @@ -225,6 +225,7 @@ func NewNibiruApp( DevGasBankKeeper: app.BankKeeper, // TODO: feat(evm): enable app/server/config flag for Evm MaxTxGasWanted. MaxTxGasWanted: DefaultMaxTxGasWanted, + EvmKeeper: app.EvmKeeper, }) app.SetAnteHandler(anteHandler) diff --git a/app/evmante_can_transfer.go b/app/evmante/evmante_can_transfer.go similarity index 88% rename from app/evmante_can_transfer.go rename to app/evmante/evmante_can_transfer.go index c2ec4b4a9..2826aa742 100644 --- a/app/evmante_can_transfer.go +++ b/app/evmante/evmante_can_transfer.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "math/big" @@ -7,24 +7,23 @@ import ( "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" + gethcommon "github.com/ethereum/go-ethereum/common" + gethcore "github.com/ethereum/go-ethereum/core/types" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/statedb" - - gethcommon "github.com/ethereum/go-ethereum/common" - gethcore "github.com/ethereum/go-ethereum/core/types" ) // CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block // context rules. type CanTransferDecorator struct { - AppKeepers + evmKeeper EVMKeeper } // NewCanTransferDecorator creates a new CanTransferDecorator instance. -func NewCanTransferDecorator(k AppKeepers) CanTransferDecorator { +func NewCanTransferDecorator(k EVMKeeper) CanTransferDecorator { return CanTransferDecorator{ - AppKeepers: k, + evmKeeper: k, } } @@ -33,8 +32,8 @@ func NewCanTransferDecorator(k AppKeepers) CanTransferDecorator { func (ctd CanTransferDecorator) AnteHandle( ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler, ) (sdk.Context, error) { - params := ctd.EvmKeeper.GetParams(ctx) - ethCfg := evm.EthereumConfig(ctd.EvmKeeper.EthChainID(ctx)) + params := ctd.evmKeeper.GetParams(ctx) + ethCfg := evm.EthereumConfig(ctd.evmKeeper.EthChainID(ctx)) signer := gethcore.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight())) for _, msg := range tx.GetMsgs() { @@ -45,7 +44,7 @@ func (ctd CanTransferDecorator) AnteHandle( "invalid message type %T, expected %T", msg, (*evm.MsgEthereumTx)(nil), ) } - baseFee := ctd.EvmKeeper.GetBaseFee(ctx) + baseFee := ctd.evmKeeper.GetBaseFee(ctx) coreMsg, err := msgEthTx.AsMessage(signer, baseFee) if err != nil { @@ -79,10 +78,10 @@ func (ctd CanTransferDecorator) AnteHandle( stateDB := statedb.New( ctx, - &ctd.EvmKeeper, + ctd.evmKeeper, statedb.NewEmptyTxConfig(gethcommon.BytesToHash(ctx.HeaderHash().Bytes())), ) - evmInstance := ctd.EvmKeeper.NewEVM(ctx, coreMsg, cfg, evm.NewNoOpTracer(), stateDB) + evmInstance := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evm.NewNoOpTracer(), stateDB) // check that caller has enough balance to cover asset transfer for **topmost** call // NOTE: here the gas consumed is from the context with the infinite gas meter diff --git a/app/evmante_can_transfer_test.go b/app/evmante/evmante_can_transfer_test.go similarity index 84% rename from app/evmante_can_transfer_test.go rename to app/evmante/evmante_can_transfer_test.go index 4e70e06a1..139e9600a 100644 --- a/app/evmante_can_transfer_test.go +++ b/app/evmante/evmante_can_transfer_test.go @@ -1,12 +1,13 @@ -package app_test +package evmante_test import ( "math/big" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -25,7 +26,7 @@ func (s *TestSuite) TestCanTransferDecorator() { sdb.AddBalance(deps.Sender.EthAddr, big.NewInt(100)) }, txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - txMsg := happyTransfertTx(deps, 0) + txMsg := evmtestutil.HappyTransferTx(deps, 0) txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() gethSigner := deps.Sender.GethSigner(deps.Chain.EvmKeeper.EthChainID(deps.Ctx)) @@ -43,7 +44,7 @@ func (s *TestSuite) TestCanTransferDecorator() { { name: "sad: signed tx, insufficient funds", txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - txMsg := happyTransfertTx(deps, 0) + txMsg := evmtestutil.HappyTransferTx(deps, 0) txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() gethSigner := deps.Sender.GethSigner(deps.Chain.EvmKeeper.EthChainID(deps.Ctx)) @@ -61,7 +62,7 @@ func (s *TestSuite) TestCanTransferDecorator() { { name: "sad: unsigned tx", txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - txMsg := happyTransfertTx(deps, 0) + txMsg := evmtestutil.HappyTransferTx(deps, 0) txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() tx, err := txMsg.BuildTx(txBuilder, eth.EthBaseDenom) @@ -74,7 +75,7 @@ func (s *TestSuite) TestCanTransferDecorator() { { name: "sad: tx with non evm message", txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - return nonEvmMsgTx(deps).(sdk.FeeTx) + return evmtestutil.NonEvmMsgTx(deps).(sdk.FeeTx) }, wantErr: "invalid message", }, @@ -84,7 +85,7 @@ func (s *TestSuite) TestCanTransferDecorator() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewCanTransferDecorator(deps.Chain.AppKeepers) + anteDec := evmante.NewCanTransferDecorator(&deps.Chain.AppKeepers.EvmKeeper) tx := tc.txSetup(&deps) if tc.ctxSetup != nil { @@ -97,7 +98,7 @@ func (s *TestSuite) TestCanTransferDecorator() { } _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/evmante_emit_event.go b/app/evmante/evmante_emit_event.go similarity index 88% rename from app/evmante_emit_event.go rename to app/evmante/evmante_emit_event.go index b621a8dbe..0470965bb 100644 --- a/app/evmante_emit_event.go +++ b/app/evmante/evmante_emit_event.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "strconv" @@ -13,12 +13,14 @@ import ( // EthEmitEventDecorator emit events in ante handler in case of tx execution failed (out of block gas limit). type EthEmitEventDecorator struct { - AppKeepers + evmKeeper EVMKeeper } // NewEthEmitEventDecorator creates a new EthEmitEventDecorator -func NewEthEmitEventDecorator(k AppKeepers) EthEmitEventDecorator { - return EthEmitEventDecorator{AppKeepers: k} +func NewEthEmitEventDecorator(k EVMKeeper) EthEmitEventDecorator { + return EthEmitEventDecorator{ + evmKeeper: k, + } } // AnteHandle emits some basic events for the eth messages @@ -28,7 +30,7 @@ func (eeed EthEmitEventDecorator) AnteHandle( // After eth tx passed ante handler, the fee is deducted and nonce increased, // it shouldn't be ignored by json-rpc. We need to emit some events at the // very end of ante handler to be indexed by the consensus engine. - txIndex := eeed.EvmKeeper.EVMState().BlockTxIndex.GetOr(ctx, 0) + txIndex := eeed.evmKeeper.EVMState().BlockTxIndex.GetOr(ctx, 0) for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evm.MsgEthereumTx) diff --git a/app/evmante_emit_event_test.go b/app/evmante/evmante_emit_event_test.go similarity index 84% rename from app/evmante_emit_event_test.go rename to app/evmante/evmante_emit_event_test.go index 39aa1351f..0b90881cc 100644 --- a/app/evmante_emit_event_test.go +++ b/app/evmante/evmante_emit_event_test.go @@ -1,12 +1,13 @@ -package app_test +package evmante_test import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + "github.com/NibiruChain/nibiru/app/evmante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm" - "github.com/NibiruChain/nibiru/app" "github.com/NibiruChain/nibiru/x/evm/evmtest" tf "github.com/NibiruChain/nibiru/x/tokenfactory/types" ) @@ -31,7 +32,7 @@ func (s *TestSuite) TestEthEmitEventDecorator() { { name: "happy: eth tx emitted event", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) return tx }, wantErr: "", @@ -42,13 +43,13 @@ func (s *TestSuite) TestEthEmitEventDecorator() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewEthEmitEventDecorator(deps.Chain.AppKeepers) + anteDec := evmante.NewEthEmitEventDecorator(&deps.Chain.AppKeepers.EvmKeeper) tx := tc.txSetup(&deps) s.Require().NoError(stateDB.Commit()) _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/evmante_fees.go b/app/evmante/evmante_fees.go similarity index 92% rename from app/evmante_fees.go rename to app/evmante/evmante_fees.go index 0e180d7e5..d6a5ef6ae 100644 --- a/app/evmante_fees.go +++ b/app/evmante/evmante_fees.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "math/big" @@ -7,7 +7,6 @@ import ( "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" - gethcore "github.com/ethereum/go-ethereum/core/types" "github.com/NibiruChain/nibiru/x/evm" @@ -21,13 +20,15 @@ var _ sdk.AnteDecorator = EthMinGasPriceDecorator{} // fee market params (EIP-1559) are enabled. // If fee is high enough, then call next AnteHandler type EthMinGasPriceDecorator struct { - AppKeepers + evmKeeper EVMKeeper } // NewEthMinGasPriceDecorator creates a new MinGasPriceDecorator instance used only for // Ethereum transactions. -func NewEthMinGasPriceDecorator(k AppKeepers) EthMinGasPriceDecorator { - return EthMinGasPriceDecorator{AppKeepers: k} +func NewEthMinGasPriceDecorator(k EVMKeeper) EthMinGasPriceDecorator { + return EthMinGasPriceDecorator{ + evmKeeper: k, + } } // AnteHandle ensures that the effective fee from the transaction is greater than the @@ -36,7 +37,7 @@ func (empd EthMinGasPriceDecorator) AnteHandle( ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler, ) (newCtx sdk.Context, err error) { minGasPrices := ctx.MinGasPrices() - evmParams := empd.EvmKeeper.GetParams(ctx) + evmParams := empd.evmKeeper.GetParams(ctx) evmDenom := evmParams.GetEvmDenom() minGasPrice := minGasPrices.AmountOf(evmDenom) @@ -45,7 +46,7 @@ func (empd EthMinGasPriceDecorator) AnteHandle( return next(ctx, tx, simulate) } - baseFee := empd.EvmKeeper.GetBaseFee(ctx) + baseFee := empd.evmKeeper.GetBaseFee(ctx) for _, msg := range tx.GetMsgs() { ethMsg, ok := msg.(*evm.MsgEthereumTx) diff --git a/app/evmante_fees_test.go b/app/evmante/evmante_fees_test.go similarity index 84% rename from app/evmante_fees_test.go rename to app/evmante/evmante_fees_test.go index f2ac7238b..875949738 100644 --- a/app/evmante_fees_test.go +++ b/app/evmante/evmante_fees_test.go @@ -1,10 +1,11 @@ -package app_test +package evmante_test import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" ) @@ -18,7 +19,7 @@ func (s *TestSuite) TestEthMinGasPriceDecorator() { { name: "happy: min gas price is 0", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) return tx }, wantErr: "", @@ -34,7 +35,7 @@ func (s *TestSuite) TestEthMinGasPriceDecorator() { WithIsCheckTx(true) }, txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) return tx }, wantErr: "", @@ -50,7 +51,7 @@ func (s *TestSuite) TestEthMinGasPriceDecorator() { WithIsCheckTx(true) }, txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) return tx }, wantErr: "insufficient fee", @@ -82,7 +83,7 @@ func (s *TestSuite) TestEthMinGasPriceDecorator() { for _, tc := range testCases { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() - anteDec := app.NewEthMinGasPriceDecorator(deps.Chain.AppKeepers) + anteDec := evmante.NewEthMinGasPriceDecorator(&deps.Chain.AppKeepers.EvmKeeper) tx := tc.txSetup(&deps) @@ -91,7 +92,7 @@ func (s *TestSuite) TestEthMinGasPriceDecorator() { } _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/evmante_gas_consume.go b/app/evmante/evmante_gas_consume.go similarity index 93% rename from app/evmante_gas_consume.go rename to app/evmante/evmante_gas_consume.go index b50613e99..af0ac423c 100644 --- a/app/evmante_gas_consume.go +++ b/app/evmante/evmante_gas_consume.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "math" @@ -7,7 +7,6 @@ import ( "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" - gethcommon "github.com/ethereum/go-ethereum/common" "github.com/NibiruChain/nibiru/eth" @@ -18,21 +17,17 @@ import ( // AnteDecEthGasConsume validates enough intrinsic gas for the transaction and // gas consumption. type AnteDecEthGasConsume struct { - AppKeepers - // bankKeeper anteutils.BankKeeper - // distributionKeeper anteutils.DistributionKeeper - // evmKeeper EVMKeeper - // stakingKeeper anteutils.StakingKeeper + evmKeeper EVMKeeper maxGasWanted uint64 } // NewAnteDecEthGasConsume creates a new EthGasConsumeDecorator func NewAnteDecEthGasConsume( - keepers AppKeepers, + k EVMKeeper, maxGasWanted uint64, ) AnteDecEthGasConsume { return AnteDecEthGasConsume{ - AppKeepers: keepers, + evmKeeper: k, maxGasWanted: maxGasWanted, } } @@ -70,14 +65,14 @@ func (anteDec AnteDecEthGasConsume) AnteHandle( return next(newCtx, tx, simulate) } - evmParams := anteDec.EvmKeeper.GetParams(ctx) + evmParams := anteDec.evmKeeper.GetParams(ctx) evmDenom := evmParams.GetEvmDenom() var events sdk.Events // Use the lowest priority of all the messages as the final one. minPriority := int64(math.MaxInt64) - baseFee := anteDec.EvmKeeper.GetBaseFee(ctx) + baseFee := anteDec.evmKeeper.GetBaseFee(ctx) for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evm.MsgEthereumTx) @@ -170,7 +165,7 @@ func (anteDec AnteDecEthGasConsume) deductFee(ctx sdk.Context, fees sdk.Coins, f // If the account balance is not sufficient, try to withdraw enough staking rewards - if err := anteDec.EvmKeeper.DeductTxCostsFromUserBalance(ctx, fees, gethcommon.BytesToAddress(feePayer)); err != nil { + if err := anteDec.evmKeeper.DeductTxCostsFromUserBalance(ctx, fees, gethcommon.BytesToAddress(feePayer)); err != nil { return errors.Wrapf(err, "failed to deduct transaction costs from user balance") } return nil diff --git a/app/evmante_gas_consume_test.go b/app/evmante/evmante_gas_consume_test.go similarity index 82% rename from app/evmante_gas_consume_test.go rename to app/evmante/evmante_gas_consume_test.go index 8918a20a9..1616c32ff 100644 --- a/app/evmante_gas_consume_test.go +++ b/app/evmante/evmante_gas_consume_test.go @@ -1,12 +1,13 @@ -package app_test +package evmante_test import ( "math/big" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" @@ -28,7 +29,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { balance := new(big.Int).Add(gasLimit, big.NewInt(100)) sdb.AddBalance(deps.Sender.EthAddr, balance) }, - txSetup: happyCreateContractTx, + txSetup: evmtestutil.HappyCreateContractTx, wantErr: "", gasMeter: eth.NewInfiniteGasMeterWithLimit(happyGasLimit().Uint64()), maxGasWanted: 0, @@ -38,7 +39,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { deps.Ctx = deps.Ctx.WithIsReCheckTx(true) }, - txSetup: happyCreateContractTx, + txSetup: evmtestutil.HappyCreateContractTx, gasMeter: eth.NewInfiniteGasMeterWithLimit(0), wantErr: "", }, @@ -49,7 +50,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { balance := new(big.Int).Add(gasLimit, big.NewInt(100)) sdb.AddBalance(deps.Sender.EthAddr, balance) }, - txSetup: happyCreateContractTx, + txSetup: evmtestutil.HappyCreateContractTx, wantErr: "exceeds block gas limit (0)", gasMeter: eth.NewInfiniteGasMeterWithLimit(0), maxGasWanted: 0, @@ -60,8 +61,8 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewAnteDecEthGasConsume( - deps.Chain.AppKeepers, tc.maxGasWanted, + anteDec := evmante.NewAnteDecEthGasConsume( + &deps.Chain.AppKeepers.EvmKeeper, tc.maxGasWanted, ) tc.beforeTxSetup(&deps, stateDB) @@ -71,7 +72,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { deps.Ctx = deps.Ctx.WithIsCheckTx(true) deps.Ctx = deps.Ctx.WithBlockGasMeter(tc.gasMeter) _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/evmante/evmante_handler.go b/app/evmante/evmante_handler.go new file mode 100644 index 000000000..84faefc89 --- /dev/null +++ b/app/evmante/evmante_handler.go @@ -0,0 +1,29 @@ +// Copyright (c) 2023-2024 Nibi, Inc. +package evmante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/NibiruChain/nibiru/app/ante" +) + +// NewAnteHandlerEVM creates the default ante handler for Ethereum transactions +func NewAnteHandlerEVM( + options ante.AnteHandlerOptions, +) sdk.AnteHandler { + return sdk.ChainAnteDecorators( + // outermost AnteDecorator. SetUpContext must be called first + NewEthSetUpContextDecorator(&options.EvmKeeper), + // Check eth effective gas price against the global MinGasPrice + NewEthMinGasPriceDecorator(&options.EvmKeeper), + NewEthValidateBasicDecorator(&options.EvmKeeper), + NewEthSigVerificationDecorator(&options.EvmKeeper), + NewAnteDecVerifyEthAcc(&options.EvmKeeper, options.AccountKeeper), + NewCanTransferDecorator(&options.EvmKeeper), + NewAnteDecEthGasConsume(&options.EvmKeeper, options.MaxTxGasWanted), + NewAnteDecEthIncrementSenderSequence(&options.EvmKeeper, options.AccountKeeper), + ante.AnteDecoratorGasWanted{}, + // emit eth tx hash and index at the very last ante handler. + NewEthEmitEventDecorator(&options.EvmKeeper), + ) +} diff --git a/app/evmante_handler_test.go b/app/evmante/evmante_handler_test.go similarity index 84% rename from app/evmante_handler_test.go rename to app/evmante/evmante_handler_test.go index e60b075b1..8fbc58c4c 100644 --- a/app/evmante_handler_test.go +++ b/app/evmante/evmante_handler_test.go @@ -1,4 +1,4 @@ -package app_test +package evmante_test import ( "math/big" @@ -8,9 +8,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/NibiruChain/nibiru/app" "github.com/NibiruChain/nibiru/app/ante" + "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -28,14 +29,14 @@ func (s *TestSuite) TestAnteHandlerEVM() { beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { sdb.AddBalance( deps.Sender.EthAddr, - new(big.Int).Add(gasLimitCreateContract(), big.NewInt(100)), + new(big.Int).Add(evmtestutil.GasLimitCreateContract(), big.NewInt(100)), ) }, ctxSetup: func(deps *evmtest.TestDeps) { gasPrice := sdk.NewInt64Coin("unibi", 1) cp := &tmproto.ConsensusParams{ Block: &tmproto.BlockParams{ - MaxGas: new(big.Int).Add(gasLimitCreateContract(), big.NewInt(100)).Int64(), + MaxGas: new(big.Int).Add(evmtestutil.GasLimitCreateContract(), big.NewInt(100)).Int64(), }, } deps.Ctx = deps.Ctx. @@ -46,7 +47,7 @@ func (s *TestSuite) TestAnteHandlerEVM() { WithConsensusParams(cp) }, txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - txMsg := happyTransfertTx(deps, 0) + txMsg := evmtestutil.HappyTransferTx(deps, 0) txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() gethSigner := deps.Sender.GethSigner(deps.Chain.EvmKeeper.EthChainID(deps.Ctx)) @@ -68,8 +69,8 @@ func (s *TestSuite) TestAnteHandlerEVM() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteHandlerEVM := app.NewAnteHandlerEVM( - deps.Chain.AppKeepers, ante.AnteHandlerOptions{ + anteHandlerEVM := evmante.NewAnteHandlerEVM( + ante.AnteHandlerOptions{ HandlerOptions: authante.HandlerOptions{ AccountKeeper: deps.Chain.AccountKeeper, BankKeeper: deps.Chain.BankKeeper, @@ -78,6 +79,7 @@ func (s *TestSuite) TestAnteHandlerEVM() { SigGasConsumer: authante.DefaultSigVerificationGasConsumer, ExtensionOptionChecker: func(*codectypes.Any) bool { return true }, }, + EvmKeeper: deps.Chain.EvmKeeper, }) tx := tc.txSetup(&deps) diff --git a/app/evmante_increment_sender_seq.go b/app/evmante/evmante_increment_sender_seq.go similarity index 84% rename from app/evmante_increment_sender_seq.go rename to app/evmante/evmante_increment_sender_seq.go index ef4ac75a5..d033b66a8 100644 --- a/app/evmante_increment_sender_seq.go +++ b/app/evmante/evmante_increment_sender_seq.go @@ -1,11 +1,11 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" - + "github.com/cosmos/cosmos-sdk/x/auth/ante" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/NibiruChain/nibiru/x/evm" @@ -13,13 +13,15 @@ import ( // AnteDecEthIncrementSenderSequence increments the sequence of the signers. type AnteDecEthIncrementSenderSequence struct { - AppKeepers + evmKeeper EVMKeeper + accountKeeper ante.AccountKeeper } // NewAnteDecEthIncrementSenderSequence creates a new EthIncrementSenderSequenceDecorator. -func NewAnteDecEthIncrementSenderSequence(k AppKeepers) AnteDecEthIncrementSenderSequence { +func NewAnteDecEthIncrementSenderSequence(k EVMKeeper, ak ante.AccountKeeper) AnteDecEthIncrementSenderSequence { return AnteDecEthIncrementSenderSequence{ - AppKeepers: k, + evmKeeper: k, + accountKeeper: ak, } } @@ -47,7 +49,7 @@ func (issd AnteDecEthIncrementSenderSequence) AnteHandle( } // increase sequence of sender - acc := issd.AccountKeeper.GetAccount(ctx, msgEthTx.GetFrom()) + acc := issd.accountKeeper.GetAccount(ctx, msgEthTx.GetFrom()) if acc == nil { return ctx, errors.Wrapf( errortypes.ErrUnknownAddress, @@ -69,7 +71,7 @@ func (issd AnteDecEthIncrementSenderSequence) AnteHandle( return ctx, errors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1) } - issd.AccountKeeper.SetAccount(ctx, acc) + issd.accountKeeper.SetAccount(ctx, acc) } return next(ctx, tx, simulate) diff --git a/app/evmante_increment_sender_seq_test.go b/app/evmante/evmante_increment_sender_seq_test.go similarity index 78% rename from app/evmante_increment_sender_seq_test.go rename to app/evmante/evmante_increment_sender_seq_test.go index 7778522e0..38831408c 100644 --- a/app/evmante_increment_sender_seq_test.go +++ b/app/evmante/evmante_increment_sender_seq_test.go @@ -1,11 +1,12 @@ -package app_test +package evmante_test import ( "math/big" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -25,7 +26,7 @@ func (s *TestSuite) TestAnteDecEthIncrementSenderSequence() { sdb.AddBalance(deps.Sender.EthAddr, balance) }, txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - return happyTransfertTx(deps, 0) + return evmtestutil.HappyTransferTx(deps, 0) }, wantErr: "", wantSeq: 1, @@ -37,8 +38,8 @@ func (s *TestSuite) TestAnteDecEthIncrementSenderSequence() { sdb.AddBalance(deps.Sender.EthAddr, balance) }, txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - txMsgOne := happyTransfertTx(deps, 0) - txMsgTwo := happyTransfertTx(deps, 1) + txMsgOne := evmtestutil.HappyTransferTx(deps, 0) + txMsgTwo := evmtestutil.HappyTransferTx(deps, 1) txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() s.Require().NoError(txBuilder.SetMsgs(txMsgOne, txMsgTwo)) @@ -52,13 +53,13 @@ func (s *TestSuite) TestAnteDecEthIncrementSenderSequence() { { name: "sad: account does not exists", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - return happyTransfertTx(deps, 0) + return evmtestutil.HappyTransferTx(deps, 0) }, wantErr: "unknown address", }, { name: "sad: tx with non evm message", - txSetup: nonEvmMsgTx, + txSetup: evmtestutil.NonEvmMsgTx, wantErr: "invalid message", }, } @@ -67,7 +68,7 @@ func (s *TestSuite) TestAnteDecEthIncrementSenderSequence() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewAnteDecEthIncrementSenderSequence(deps.Chain.AppKeepers) + anteDec := evmante.NewAnteDecEthIncrementSenderSequence(&deps.Chain.EvmKeeper, deps.Chain.AccountKeeper) if tc.beforeTxSetup != nil { tc.beforeTxSetup(&deps, stateDB) @@ -76,7 +77,7 @@ func (s *TestSuite) TestAnteDecEthIncrementSenderSequence() { tx := tc.txSetup(&deps) _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/evmante_setup_ctx.go b/app/evmante/evmante_setup_ctx.go similarity index 88% rename from app/evmante_setup_ctx.go rename to app/evmante/evmante_setup_ctx.go index be4d5f897..6cad962a7 100644 --- a/app/evmante_setup_ctx.go +++ b/app/evmante/evmante_setup_ctx.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( errorsmod "cosmossdk.io/errors" @@ -12,12 +12,12 @@ import ( // EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption // by setting the gas meter to infinite type EthSetupContextDecorator struct { - AppKeepers + evmKeeper EVMKeeper } -func NewEthSetUpContextDecorator(k AppKeepers) EthSetupContextDecorator { +func NewEthSetUpContextDecorator(k EVMKeeper) EthSetupContextDecorator { return EthSetupContextDecorator{ - AppKeepers: k, + evmKeeper: k, } } @@ -43,6 +43,6 @@ func (esc EthSetupContextDecorator) AnteHandle( // Reset transient gas used to prepare the execution of current cosmos tx. // Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs. - esc.EvmKeeper.ResetTransientGasUsed(ctx) + esc.evmKeeper.ResetTransientGasUsed(ctx) return next(newCtx, tx, simulate) } diff --git a/app/evmante_setup_ctx_test.go b/app/evmante/evmante_setup_ctx_test.go similarity index 68% rename from app/evmante_setup_ctx_test.go rename to app/evmante/evmante_setup_ctx_test.go index 132ed8f1a..7bdd25f08 100644 --- a/app/evmante_setup_ctx_test.go +++ b/app/evmante/evmante_setup_ctx_test.go @@ -1,4 +1,4 @@ -package app_test +package evmante_test import ( "math" @@ -6,24 +6,25 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" ) func (s *TestSuite) TestEthSetupContextDecorator() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewEthSetUpContextDecorator(deps.Chain.AppKeepers) + anteDec := evmante.NewEthSetUpContextDecorator(&deps.Chain.EvmKeeper) s.Require().NoError(stateDB.Commit()) - tx := happyCreateContractTx(&deps) + tx := evmtestutil.HappyCreateContractTx(&deps) // Set block gas used to non 0 to check that handler resets it - anteDec.EvmKeeper.EvmState.BlockGasUsed.Set(deps.Ctx, 1000) + deps.Chain.EvmKeeper.EvmState.BlockGasUsed.Set(deps.Ctx, 1000) // Ante handler returns new context newCtx, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) s.Require().NoError(err) @@ -37,7 +38,7 @@ func (s *TestSuite) TestEthSetupContextDecorator() { s.Require().Equal(defaultGasConfig, newCtx.TransientKVGasConfig()) // Check that block gas used is reset to 0 - gas, err := anteDec.EvmKeeper.EvmState.BlockGasUsed.Get(newCtx) + gas, err := deps.Chain.EvmKeeper.EvmState.BlockGasUsed.Get(newCtx) s.Require().NoError(err) s.Require().Equal(gas, uint64(0)) } diff --git a/app/evmante_sigverify.go b/app/evmante/evmante_sigverify.go similarity index 90% rename from app/evmante_sigverify.go rename to app/evmante/evmante_sigverify.go index 314681cd8..2c41da448 100644 --- a/app/evmante_sigverify.go +++ b/app/evmante/evmante_sigverify.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "math/big" @@ -14,13 +14,13 @@ import ( // EthSigVerificationDecorator validates an ethereum signatures type EthSigVerificationDecorator struct { - AppKeepers + evmKeeper EVMKeeper } // NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator -func NewEthSigVerificationDecorator(k AppKeepers) EthSigVerificationDecorator { +func NewEthSigVerificationDecorator(k EVMKeeper) EthSigVerificationDecorator { return EthSigVerificationDecorator{ - AppKeepers: k, + evmKeeper: k, } } @@ -32,8 +32,8 @@ func NewEthSigVerificationDecorator(k AppKeepers) EthSigVerificationDecorator { func (esvd EthSigVerificationDecorator) AnteHandle( ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler, ) (newCtx sdk.Context, err error) { - chainID := esvd.EvmKeeper.EthChainID(ctx) - evmParams := esvd.EvmKeeper.GetParams(ctx) + chainID := esvd.evmKeeper.EthChainID(ctx) + evmParams := esvd.evmKeeper.GetParams(ctx) ethCfg := evm.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) signer := gethcore.MakeSigner(ethCfg, blockNum) diff --git a/app/evmante_sigverify_test.go b/app/evmante/evmante_sigverify_test.go similarity index 79% rename from app/evmante_sigverify_test.go rename to app/evmante/evmante_sigverify_test.go index 145174e09..de64c9dc6 100644 --- a/app/evmante_sigverify_test.go +++ b/app/evmante/evmante_sigverify_test.go @@ -1,4 +1,4 @@ -package app_test +package evmante_test import ( "math/big" @@ -6,14 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" tf "github.com/NibiruChain/nibiru/x/tokenfactory/types" ) -var ( - InvalidChainID = big.NewInt(987654321) -) +var InvalidChainID = big.NewInt(987654321) func (s *TestSuite) TestEthSigVerificationDecorator() { testCases := []struct { @@ -24,7 +23,7 @@ func (s *TestSuite) TestEthSigVerificationDecorator() { { name: "sad: unsigned tx", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) return tx }, wantErr: "rejected unprotected Ethereum transaction", @@ -43,7 +42,7 @@ func (s *TestSuite) TestEthSigVerificationDecorator() { { name: "sad: ethereum tx invalid chain id", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) gethSigner := deps.Sender.GethSigner(InvalidChainID) keyringSigner := deps.Sender.KeyringSigner err := tx.Sign(gethSigner, keyringSigner) @@ -55,7 +54,7 @@ func (s *TestSuite) TestEthSigVerificationDecorator() { { name: "happy: signed ethereum tx", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) gethSigner := deps.Sender.GethSigner(deps.Chain.EvmKeeper.EthChainID(deps.Ctx)) keyringSigner := deps.Sender.KeyringSigner err := tx.Sign(gethSigner, keyringSigner) @@ -70,14 +69,14 @@ func (s *TestSuite) TestEthSigVerificationDecorator() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewEthSigVerificationDecorator(deps.Chain.AppKeepers) + anteDec := evmante.NewEthSigVerificationDecorator(&deps.Chain.AppKeepers.EvmKeeper) tx := tc.txSetup(&deps) s.Require().NoError(stateDB.Commit()) deps.Ctx = deps.Ctx.WithIsCheckTx(true) _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/evmante_validate_basic.go b/app/evmante/evmante_validate_basic.go similarity index 95% rename from app/evmante_validate_basic.go rename to app/evmante/evmante_validate_basic.go index 2c006485a..22f599f8b 100644 --- a/app/evmante_validate_basic.go +++ b/app/evmante/evmante_validate_basic.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "errors" @@ -15,13 +15,13 @@ import ( // EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures type EthValidateBasicDecorator struct { - AppKeepers + evmKeeper EVMKeeper } // NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator -func NewEthValidateBasicDecorator(k AppKeepers) EthValidateBasicDecorator { +func NewEthValidateBasicDecorator(k EVMKeeper) EthValidateBasicDecorator { return EthValidateBasicDecorator{ - AppKeepers: k, + evmKeeper: k, } } @@ -89,8 +89,8 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu txFee := sdk.Coins{} txGasLimit := uint64(0) - evmParams := vbd.EvmKeeper.GetParams(ctx) - baseFee := vbd.EvmKeeper.GetBaseFee(ctx) + evmParams := vbd.evmKeeper.GetParams(ctx) + baseFee := vbd.evmKeeper.GetBaseFee(ctx) enableCreate := evmParams.GetEnableCreate() enableCall := evmParams.GetEnableCall() evmDenom := evmParams.GetEvmDenom() diff --git a/app/evmante_validate_basic_test.go b/app/evmante/evmante_validate_basic_test.go similarity index 89% rename from app/evmante_validate_basic_test.go rename to app/evmante/evmante_validate_basic_test.go index f3b74d4fc..77b59c44b 100644 --- a/app/evmante_validate_basic_test.go +++ b/app/evmante/evmante_validate_basic_test.go @@ -1,4 +1,4 @@ -package app_test +package evmante_test import ( "math/big" @@ -10,9 +10,10 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" "github.com/NibiruChain/nibiru/x/common/testutil" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" ) @@ -29,7 +30,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { name: "happy: properly built eth tx", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() - tx, err := happyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) + tx, err := evmtestutil.HappyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) s.Require().NoError(err) return tx }, @@ -41,21 +42,21 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { deps.Ctx = deps.Ctx.WithIsReCheckTx(true) }, txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - return happyCreateContractTx(deps) + return evmtestutil.HappyCreateContractTx(deps) }, wantErr: "", }, { name: "sad: fail chain id basic validation", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - return happyCreateContractTx(deps) + return evmtestutil.HappyCreateContractTx(deps) }, wantErr: "invalid chain-id", }, { name: "sad: tx not implementing protoTxProvider", txSetup: func(deps *evmtest.TestDeps) sdk.Tx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) gethSigner := deps.Sender.GethSigner(InvalidChainID) keyringSigner := deps.Sender.KeyringSigner err := tx.Sign(gethSigner, keyringSigner) @@ -69,7 +70,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { txSetup: func(deps *evmtest.TestDeps) sdk.Tx { txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() txBuilder.SetMemo("memo") - tx, err := happyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) + tx, err := evmtestutil.HappyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) s.Require().NoError(err) return tx }, @@ -80,7 +81,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { txSetup: func(deps *evmtest.TestDeps) sdk.Tx { txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() txBuilder.SetFeePayer(testutil.AccAddress()) - tx, err := happyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) + tx, err := evmtestutil.HappyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) s.Require().NoError(err) return tx }, @@ -91,7 +92,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { txSetup: func(deps *evmtest.TestDeps) sdk.Tx { txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() txBuilder.SetFeeGranter(testutil.AccAddress()) - tx, err := happyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) + tx, err := evmtestutil.HappyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) s.Require().NoError(err) return tx }, @@ -111,7 +112,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { } err := txBuilder.SetSignatures(sigV2) s.Require().NoError(err) - txMsg := happyCreateContractTx(deps) + txMsg := evmtestutil.HappyCreateContractTx(deps) gethSigner := deps.Sender.GethSigner(deps.Chain.EvmKeeper.EthChainID(deps.Ctx)) keyringSigner := deps.Sender.KeyringSigner @@ -133,7 +134,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { }, txSetup: func(deps *evmtest.TestDeps) sdk.Tx { txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() - tx, err := happyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) + tx, err := evmtestutil.HappyCreateContractTx(deps).BuildTx(txBuilder, eth.EthBaseDenom) s.Require().NoError(err) return tx }, @@ -220,7 +221,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewEthValidateBasicDecorator(deps.Chain.AppKeepers) + anteDec := evmante.NewEthValidateBasicDecorator(&deps.Chain.AppKeepers.EvmKeeper) tx := tc.txSetup(&deps) s.Require().NoError(stateDB.Commit()) @@ -232,7 +233,7 @@ func (s *TestSuite) TestEthValidateBasicDecorator() { deps.K.SetParams(deps.Ctx, tc.paramsSetup(&deps)) } _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) diff --git a/app/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go similarity index 85% rename from app/evmante_verify_eth_acc.go rename to app/evmante/evmante_verify_eth_acc.go index 6832bc06e..d3bb8a4f0 100644 --- a/app/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -1,34 +1,29 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" + gethcommon "github.com/ethereum/go-ethereum/common" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/keeper" "github.com/NibiruChain/nibiru/x/evm/statedb" - - gethcommon "github.com/ethereum/go-ethereum/common" -) - -var ( - _ sdk.AnteDecorator = (*AnteDecEthGasConsume)(nil) - _ sdk.AnteDecorator = (*AnteDecVerifyEthAcc)(nil) ) // AnteDecVerifyEthAcc validates an account balance checks type AnteDecVerifyEthAcc struct { - AppKeepers + evmKeeper EVMKeeper + accountKeeper evm.AccountKeeper } // NewAnteDecVerifyEthAcc creates a new EthAccountVerificationDecorator -func NewAnteDecVerifyEthAcc(k AppKeepers) AnteDecVerifyEthAcc { +func NewAnteDecVerifyEthAcc(k EVMKeeper, ak evm.AccountKeeper) AnteDecVerifyEthAcc { return AnteDecVerifyEthAcc{ - AppKeepers: k, + evmKeeper: k, + accountKeeper: ak, } } @@ -67,11 +62,11 @@ func (anteDec AnteDecVerifyEthAcc) AnteHandle( // check whether the sender address is EOA fromAddr := gethcommon.BytesToAddress(from) - acct := anteDec.EvmKeeper.GetAccount(ctx, fromAddr) + acct := anteDec.evmKeeper.GetAccount(ctx, fromAddr) if acct == nil { - acc := anteDec.AccountKeeper.NewAccountWithAddress(ctx, from) - anteDec.AccountKeeper.SetAccount(ctx, acc) + acc := anteDec.accountKeeper.NewAccountWithAddress(ctx, from) + anteDec.accountKeeper.SetAccount(ctx, acc) acct = statedb.NewEmptyAccount() } else if acct.IsContract() { return ctx, errors.Wrapf(errortypes.ErrInvalidType, diff --git a/app/evmante_verify_eth_acc_test.go b/app/evmante/evmante_verify_eth_acc_test.go similarity index 54% rename from app/evmante_verify_eth_acc_test.go rename to app/evmante/evmante_verify_eth_acc_test.go index c8f124ac0..2fa78400a 100644 --- a/app/evmante_verify_eth_acc_test.go +++ b/app/evmante/evmante_verify_eth_acc_test.go @@ -1,26 +1,17 @@ -package app_test +package evmante_test import ( "math/big" - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - gethparams "github.com/ethereum/go-ethereum/params" - "github.com/NibiruChain/nibiru/app" + "github.com/NibiruChain/nibiru/app/evmante" + evmtestutil "github.com/NibiruChain/nibiru/x/common/testutil/evm" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" - "github.com/NibiruChain/nibiru/x/evm/statedb" ) -var NextNoOpAnteHandler sdk.AnteHandler = func( - ctx sdk.Context, tx sdk.Tx, simulate bool, -) (newCtx sdk.Context, err error) { - return ctx, nil -} - func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { testCases := []struct { name string @@ -33,13 +24,13 @@ func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { sdb.AddBalance(deps.Sender.EthAddr, happyGasLimit()) }, - txSetup: happyCreateContractTx, + txSetup: evmtestutil.HappyCreateContractTx, wantErr: "", }, { name: "sad: sender has insufficient gas balance", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) {}, - txSetup: happyCreateContractTx, + txSetup: evmtestutil.HappyCreateContractTx, wantErr: "sender balance < tx cost", }, { @@ -48,7 +39,7 @@ func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { // Force account to be a smart contract sdb.SetCode(deps.Sender.EthAddr, []byte("evm bytecode stuff")) }, - txSetup: happyCreateContractTx, + txSetup: evmtestutil.HappyCreateContractTx, wantErr: "sender is not EOA", }, { @@ -63,7 +54,7 @@ func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { name: "sad: empty from addr", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) {}, txSetup: func(deps *evmtest.TestDeps) *evm.MsgEthereumTx { - tx := happyCreateContractTx(deps) + tx := evmtestutil.HappyCreateContractTx(deps) tx.From = "" return tx }, @@ -75,7 +66,7 @@ func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { s.Run(tc.name, func() { deps := evmtest.NewTestDeps() stateDB := deps.StateDB() - anteDec := app.NewAnteDecVerifyEthAcc(deps.Chain.AppKeepers) + anteDec := evmante.NewAnteDecVerifyEthAcc(&deps.Chain.AppKeepers.EvmKeeper, &deps.Chain.AppKeepers.AccountKeeper) tc.beforeTxSetup(&deps, stateDB) tx := tc.txSetup(&deps) @@ -83,7 +74,7 @@ func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { deps.Ctx = deps.Ctx.WithIsCheckTx(true) _, err := anteDec.AnteHandle( - deps.Ctx, tx, false, NextNoOpAnteHandler, + deps.Ctx, tx, false, evmtestutil.NextNoOpAnteHandler, ) if tc.wantErr != "" { s.Require().ErrorContains(err, tc.wantErr) @@ -100,48 +91,3 @@ func happyGasLimit() *big.Int { // 888 is a cushion to account for KV store reads and writes ) } - -func gasLimitCreateContract() *big.Int { - return new(big.Int).SetUint64( - gethparams.TxGasContractCreation + 700, - ) -} - -func happyCreateContractTx(deps *evmtest.TestDeps) *evm.MsgEthereumTx { - ethContractCreationTxParams := &evm.EvmTxArgs{ - ChainID: deps.Chain.EvmKeeper.EthChainID(deps.Ctx), - Nonce: 1, - Amount: big.NewInt(10), - GasLimit: gasLimitCreateContract().Uint64(), - GasPrice: big.NewInt(1), - } - tx := evm.NewTx(ethContractCreationTxParams) - tx.From = deps.Sender.EthAddr.Hex() - return tx -} - -func happyTransfertTx(deps *evmtest.TestDeps, nonce uint64) *evm.MsgEthereumTx { - to := evmtest.NewEthAccInfo().EthAddr - ethContractCreationTxParams := &evm.EvmTxArgs{ - ChainID: deps.Chain.EvmKeeper.EthChainID(deps.Ctx), - Nonce: nonce, - Amount: big.NewInt(10), - GasLimit: gasLimitCreateContract().Uint64(), - GasPrice: big.NewInt(1), - To: &to, - } - tx := evm.NewTx(ethContractCreationTxParams) - tx.From = deps.Sender.EthAddr.Hex() - return tx -} - -func nonEvmMsgTx(deps *evmtest.TestDeps) sdk.Tx { - gasLimit := uint64(10) - fees := sdk.NewCoins(sdk.NewInt64Coin("unibi", int64(gasLimit))) - msg := &banktypes.MsgSend{ - FromAddress: deps.Sender.NibiruAddr.String(), - ToAddress: evmtest.NewEthAccInfo().NibiruAddr.String(), - Amount: sdk.NewCoins(sdk.NewInt64Coin("unibi", 1)), - } - return buildTx(deps, true, msg, gasLimit, fees) -} diff --git a/app/evmante_interfaces.go b/app/evmante/interfaces.go similarity index 91% rename from app/evmante_interfaces.go rename to app/evmante/interfaces.go index dc8192bfa..09b10dab7 100644 --- a/app/evmante_interfaces.go +++ b/app/evmante/interfaces.go @@ -1,5 +1,5 @@ // Copyright (c) 2023-2024 Nibi, Inc. -package app +package evmante import ( "math/big" @@ -26,6 +26,8 @@ type EVMKeeper interface { GetParams(ctx sdk.Context) evm.Params EVMState() evmkeeper.EvmState + EthChainID(ctx sdk.Context) *big.Int + GetBaseFee(ctx sdk.Context) *big.Int } type protoTxProvider interface { diff --git a/app/evmante/suite_test.go b/app/evmante/suite_test.go new file mode 100644 index 000000000..fac4157a8 --- /dev/null +++ b/app/evmante/suite_test.go @@ -0,0 +1,77 @@ +package evmante_test + +import ( + "testing" + + "cosmossdk.io/math" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/suite" + + "github.com/NibiruChain/nibiru/app" +) + +type TestSuite struct { + suite.Suite + + encCfg app.EncodingConfig +} + +func TestAppTestSuite(t *testing.T) { + suite.Run(t, new(TestSuite)) +} + +func (s *TestSuite) SetupSuite() { + s.encCfg = app.MakeEncodingConfig() +} + +func (s *TestSuite) DefaultGenesisCopy() app.GenesisState { + return app.NewDefaultGenesisState(s.encCfg.Codec) +} + +func (s *TestSuite) TestGenesis() { + getDefaultStakingGenesis := func() *stakingtypes.GenesisState { + genStaking := new(stakingtypes.GenesisState) + s.encCfg.Codec.MustUnmarshalJSON( + app.StakingModule{}.DefaultGenesis(s.encCfg.Codec), + genStaking, + ) + return genStaking + } + + gens := []*stakingtypes.GenesisState{} + gens = append(gens, getDefaultStakingGenesis()) + + genStaking := getDefaultStakingGenesis() + genStaking.Params.MinCommissionRate = math.LegacyZeroDec() + gens = append(gens, genStaking) + + for _, tc := range []struct { + name string + gen *stakingtypes.GenesisState + wantErr string + }{ + { + name: "default should work fine", + gen: gens[0], + }, + { + name: "zero commission should fail", + gen: gens[1], + wantErr: "min_commission must be positive", + }, + } { + s.T().Run(tc.name, func(t *testing.T) { + genStakingJson := s.encCfg.Codec.MustMarshalJSON(tc.gen) + err := app.StakingModule{}.ValidateGenesis( + s.encCfg.Codec, + s.encCfg.TxConfig, + genStakingJson, + ) + if tc.wantErr != "" { + s.ErrorContains(err, tc.wantErr) + return + } + s.NoError(err) + }) + } +} diff --git a/app/evmante_fee_checker.go b/app/evmante_fee_checker.go deleted file mode 100644 index 5bc5c50f2..000000000 --- a/app/evmante_fee_checker.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2023-2024 Nibi, Inc. -package app - -import ( - "math" - - "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" - - sdk "github.com/cosmos/cosmos-sdk/types" - errortypes "github.com/cosmos/cosmos-sdk/types/errors" - authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - - "github.com/NibiruChain/nibiru/app/ante" - "github.com/NibiruChain/nibiru/eth" - "github.com/NibiruChain/nibiru/x/evm" - evmkeeper "github.com/NibiruChain/nibiru/x/evm/keeper" -) - -// NewDynamicFeeChecker returns a `TxFeeChecker` that applies a dynamic fee to -// Cosmos txs using the EIP-1559 fee market logic. -// This can be called in both CheckTx and deliverTx modes. -// a) feeCap = tx.fees / tx.gas -// b) tipFeeCap = tx.MaxPriorityPrice (default) or MaxInt64 -// - when `ExtensionOptionDynamicFeeTx` is omitted, `tipFeeCap` defaults to `MaxInt64`. -// - Tx priority is set to `effectiveGasPrice / DefaultPriorityReduction`. -func NewDynamicFeeChecker(k evmkeeper.Keeper) ante.TxFeeChecker { - return func(ctx sdk.Context, feeTx sdk.FeeTx) (sdk.Coins, int64, error) { - // TODO: in the e2e test, - // if the fee in the genesis transaction meet the baseFee and minGasPrice in the feemarket, - // we can remove this code - if ctx.BlockHeight() == 0 { - // genesis transactions: fallback to min-gas-price logic - return checkTxFeeWithValidatorMinGasPrices(ctx, feeTx) - } - params := k.GetParams(ctx) - denom := params.EvmDenom - - baseFee := k.GetBaseFee(ctx) - - // default to `MaxInt64` when there's no extension option. - maxPriorityPrice := sdkmath.NewInt(math.MaxInt64) - - // get the priority tip cap from the extension option. - if hasExtOptsTx, ok := feeTx.(authante.HasExtensionOptionsTx); ok { - for _, opt := range hasExtOptsTx.GetExtensionOptions() { - if extOpt, ok := opt.GetCachedValue().(*eth.ExtensionOptionDynamicFeeTx); ok { - maxPriorityPrice = extOpt.MaxPriorityPrice - break - } - } - } - - // priority fee cannot be negative - if maxPriorityPrice.IsNegative() { - return nil, 0, errors.Wrapf( - errortypes.ErrInsufficientFee, - "max priority price cannot be negative", - ) - } - - gas := feeTx.GetGas() - feeCoins := feeTx.GetFee() - fee := feeCoins.AmountOfNoDenomValidation(denom) - - feeCap := fee.Quo(sdkmath.NewIntFromUint64(gas)) - baseFeeInt := sdkmath.NewIntFromBigInt(baseFee) - - if feeCap.LT(baseFeeInt) { - return nil, 0, errors.Wrapf( - errortypes.ErrInsufficientFee, - "gas prices too low, got: %s%s required: %s%s. "+ - "Please retry using a higher gas price or a higher fee", - feeCap, - denom, - baseFeeInt, - denom, - ) - } - - // calculate the effective gas price using the EIP-1559 logic. - effectivePrice := sdkmath.NewIntFromBigInt( - evm.EffectiveGasPrice(baseFeeInt.BigInt(), feeCap.BigInt(), maxPriorityPrice.BigInt()), - ) - - // NOTE: create a new coins slice without having to validate the denom - effectiveFee := sdk.Coins{ - { - Denom: denom, - Amount: effectivePrice.Mul(sdkmath.NewIntFromUint64(gas)), - }, - } - - bigPriority := effectivePrice.Sub(baseFeeInt).Quo(evm.DefaultPriorityReduction) - priority := int64(math.MaxInt64) - - if bigPriority.IsInt64() { - priority = bigPriority.Int64() - } - - return effectiveFee, priority, nil - } -} - -// checkTxFeeWithValidatorMinGasPrices implements the default fee logic, where the minimum price per -// unit of gas is fixed and set by each validator, and the tx priority is computed from the gas price. -func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coins, int64, error) { - feeCoins := tx.GetFee() - minGasPrices := ctx.MinGasPrices() - gas := int64(tx.GetGas()) //#nosec G701 -- checked for int overflow on ValidateBasic() - - // Ensure that the provided fees meet a minimum threshold for the validator, - // if this is a CheckTx. This is only for local mempool purposes, and thus - // is only ran on check tx. - if ctx.IsCheckTx() && !minGasPrices.IsZero() { - requiredFees := make(sdk.Coins, len(minGasPrices)) - - // Determine the required fees by multiplying each required minimum gas - // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). - glDec := sdkmath.LegacyNewDec(gas) - for i, gp := range minGasPrices { - fee := gp.Amount.Mul(glDec) - requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) - } - - if !feeCoins.IsAnyGTE(requiredFees) { - return nil, 0, errors.Wrapf( - errortypes.ErrInsufficientFee, - "insufficient fees; got: %s required: %s", feeCoins, requiredFees, - ) - } - } - - priority := getTxPriority(feeCoins, gas) - return feeCoins, priority, nil -} - -// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price -// provided in a transaction. -func getTxPriority(fees sdk.Coins, gas int64) int64 { - var priority int64 - - for _, fee := range fees { - gasPrice := fee.Amount.QuoRaw(gas) - amt := gasPrice.Quo(evm.DefaultPriorityReduction) - p := int64(math.MaxInt64) - - if amt.IsInt64() { - p = amt.Int64() - } - - if priority == 0 || p < priority { - priority = p - } - } - - return priority -} diff --git a/app/evmante_fee_checker_test.go b/app/evmante_fee_checker_test.go deleted file mode 100644 index 184045704..000000000 --- a/app/evmante_fee_checker_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package app_test - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/NibiruChain/nibiru/app" - "github.com/NibiruChain/nibiru/eth" - "github.com/NibiruChain/nibiru/x/evm/evmtest" -) - -func (s *TestSuite) TestDynamicFeeChecker() { - testCases := []struct { - name string - txSetup func(deps *evmtest.TestDeps) sdk.FeeTx - ctxSetup func(deps *evmtest.TestDeps) - wantErr string - wantFee int64 - wantPriority int64 - }{ - { - name: "happy: genesis tx with sufficient fee", - ctxSetup: func(deps *evmtest.TestDeps) { - gasPrice := sdk.NewInt64Coin("unibi", 1) - deps.Ctx = deps.Ctx. - WithBlockHeight(0). - WithMinGasPrices( - sdk.NewDecCoins(sdk.NewDecCoinFromCoin(gasPrice)), - ). - WithIsCheckTx(true) - }, - txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - txMsg := happyCreateContractTx(deps) - txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() - tx, err := txMsg.BuildTx(txBuilder, eth.EthBaseDenom) - s.Require().NoError(err) - return tx - }, - wantErr: "", - wantFee: gasLimitCreateContract().Int64(), - wantPriority: 0, - }, - { - name: "sad: genesis tx insufficient fee", - ctxSetup: func(deps *evmtest.TestDeps) { - gasPrice := sdk.NewInt64Coin("unibi", 2) - deps.Ctx = deps.Ctx. - WithBlockHeight(0). - WithMinGasPrices( - sdk.NewDecCoins(sdk.NewDecCoinFromCoin(gasPrice)), - ). - WithIsCheckTx(true) - }, - txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - txMsg := happyCreateContractTx(deps) - txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() - tx, err := txMsg.BuildTx(txBuilder, eth.EthBaseDenom) - s.Require().NoError(err) - return tx - }, - wantErr: "insufficient fee", - }, - { - name: "happy: tx with sufficient fee", - txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { - txMsg := happyCreateContractTx(deps) - txBuilder := deps.EncCfg.TxConfig.NewTxBuilder() - tx, err := txMsg.BuildTx(txBuilder, eth.EthBaseDenom) - s.Require().NoError(err) - return tx - }, - wantErr: "", - wantFee: gasLimitCreateContract().Int64(), - wantPriority: 0, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - deps := evmtest.NewTestDeps() - checker := app.NewDynamicFeeChecker(deps.K) - - if tc.ctxSetup != nil { - tc.ctxSetup(&deps) - } - - fee, priority, err := checker(deps.Ctx, tc.txSetup(&deps)) - - if tc.wantErr != "" { - s.Require().ErrorContains(err, tc.wantErr) - return - } - s.Require().NoError(err) - s.Require().Equal(tc.wantFee, fee.AmountOf("unibi").Int64()) - s.Require().Equal(tc.wantPriority, priority) - }) - } -} diff --git a/app/evmante_handler.go b/app/evmante_handler.go deleted file mode 100644 index 74cbea3ac..000000000 --- a/app/evmante_handler.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2023-2024 Nibi, Inc. -package app - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/NibiruChain/nibiru/app/ante" -) - -// NewAnteHandlerEVM creates the default ante handler for Ethereum transactions -func NewAnteHandlerEVM( - k AppKeepers, options ante.AnteHandlerOptions, -) sdk.AnteHandler { - return sdk.ChainAnteDecorators( - // outermost AnteDecorator. SetUpContext must be called first - NewEthSetUpContextDecorator(k), - // Check eth effective gas price against the global MinGasPrice - NewEthMinGasPriceDecorator(k), - NewEthValidateBasicDecorator(k), - NewEthSigVerificationDecorator(k), - NewAnteDecVerifyEthAcc(k), - NewCanTransferDecorator(k), - NewAnteDecEthGasConsume(k, options.MaxTxGasWanted), - NewAnteDecEthIncrementSenderSequence(k), - AnteDecoratorGasWanted{}, - // emit eth tx hash and index at the very last ante handler. - NewEthEmitEventDecorator(k), - ) -} diff --git a/x/common/testutil/evm/evm.go b/x/common/testutil/evm/evm.go new file mode 100644 index 000000000..3090de617 --- /dev/null +++ b/x/common/testutil/evm/evm.go @@ -0,0 +1,87 @@ +package evmtestutil + +import ( + "math/big" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + gethparams "github.com/ethereum/go-ethereum/params" + + "github.com/NibiruChain/nibiru/x/evm" + "github.com/NibiruChain/nibiru/x/evm/evmtest" +) + +var NextNoOpAnteHandler sdk.AnteHandler = func( + ctx sdk.Context, tx sdk.Tx, simulate bool, +) (newCtx sdk.Context, err error) { + return ctx, nil +} + +func HappyTransferTx(deps *evmtest.TestDeps, nonce uint64) *evm.MsgEthereumTx { + to := evmtest.NewEthAccInfo().EthAddr + ethContractCreationTxParams := &evm.EvmTxArgs{ + ChainID: deps.Chain.EvmKeeper.EthChainID(deps.Ctx), + Nonce: nonce, + Amount: big.NewInt(10), + GasLimit: GasLimitCreateContract().Uint64(), + GasPrice: big.NewInt(1), + To: &to, + } + tx := evm.NewTx(ethContractCreationTxParams) + tx.From = deps.Sender.EthAddr.Hex() + return tx +} + +func NonEvmMsgTx(deps *evmtest.TestDeps) sdk.Tx { + gasLimit := uint64(10) + fees := sdk.NewCoins(sdk.NewInt64Coin("unibi", int64(gasLimit))) + msg := &banktypes.MsgSend{ + FromAddress: deps.Sender.NibiruAddr.String(), + ToAddress: evmtest.NewEthAccInfo().NibiruAddr.String(), + Amount: sdk.NewCoins(sdk.NewInt64Coin("unibi", 1)), + } + return buildTx(deps, true, msg, gasLimit, fees) +} + +func buildTx( + deps *evmtest.TestDeps, + ethExtentions bool, + msg sdk.Msg, + gasLimit uint64, + fees sdk.Coins, +) sdk.FeeTx { + txBuilder, _ := deps.EncCfg.TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder) + if ethExtentions { + option, _ := codectypes.NewAnyWithValue(&evm.ExtensionOptionsEthereumTx{}) + txBuilder.SetExtensionOptions(option) + } + err := txBuilder.SetMsgs(msg) + if err != nil { + panic(err) + } + txBuilder.SetGasLimit(gasLimit) + txBuilder.SetFeeAmount(fees) + + return txBuilder.GetTx() +} + +func HappyCreateContractTx(deps *evmtest.TestDeps) *evm.MsgEthereumTx { + ethContractCreationTxParams := &evm.EvmTxArgs{ + ChainID: deps.Chain.EvmKeeper.EthChainID(deps.Ctx), + Nonce: 1, + Amount: big.NewInt(10), + GasLimit: GasLimitCreateContract().Uint64(), + GasPrice: big.NewInt(1), + } + tx := evm.NewTx(ethContractCreationTxParams) + tx.From = deps.Sender.EthAddr.Hex() + return tx +} + +func GasLimitCreateContract() *big.Int { + return new(big.Int).SetUint64( + gethparams.TxGasContractCreation + 700, + ) +}