diff --git a/app/app.go b/app/app.go index a54473a593..e6b4689541 100644 --- a/app/app.go +++ b/app/app.go @@ -2016,13 +2016,17 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE }, nil } + // Prepare context for EVM transaction (set infinite gas meter like original flow) + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) + _, isAssociated := app.GigaEvmKeeper.GetEVMAddress(ctx, seiAddr) - // Run validation checks (fee/nonce/balance - stateless checks done earlier) - validation := app.validateGigaEVMTx(ctx, ethTx, sender, seiAddr, isAssociated) + // Create state DB before validation so balance checks use DBImpl hooks. + stateDB := gigaevmstate.NewDBImpl(ctx, &app.GigaEvmKeeper, false) + defer stateDB.Cleanup() - // Prepare context for EVM transaction (set infinite gas meter like original flow) - ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) + // Run validation checks (fee/nonce/balance - stateless checks done earlier) + validation := app.validateGigaEVMTx(ctx, stateDB, ethTx, sender, seiAddr, isAssociated) if validation.err != nil { // Validation failed - bump nonce via keeper if it was valid (matches V2's DeliverTxCallback @@ -2046,10 +2050,6 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE return nil, gigaprecompiles.ErrBalanceMigrationRequired } - // Create state DB for this transaction (only for valid transactions) - stateDB := gigaevmstate.NewDBImpl(ctx, &app.GigaEvmKeeper, false) - defer stateDB.Cleanup() - // Pre-charge gas fee (like V2's ante handler), then execute with feeAlreadyCharged=true. // V2 charges fees in the ante handler, then runs the EVM with feeAlreadyCharged=true // which skips buyGas/refundGas/coinbase. Without this, GasUsed differs between Giga @@ -3025,6 +3025,7 @@ type gigaValidationResult struct { // 7. Balance check func (app *App) validateGigaEVMTx( ctx sdk.Context, + stateDB *gigaevmstate.DBImpl, ethTx *ethtypes.Transaction, sender common.Address, seiAddr sdk.AccAddress, @@ -3199,13 +3200,17 @@ func (app *App) validateGigaEVMTx( balanceCheck := new(big.Int).Mul(new(big.Int).SetUint64(ethTx.Gas()), ethTx.GasFeeCap()) balanceCheck.Add(balanceCheck, ethTx.Value()) - senderBalance := app.GigaEvmKeeper.GetBalance(ctx, seiAddr) + // Route validation balance reads through DBImpl so mock_balances follows + // the same ensureMinimumBalance behavior as V2's StateTransition.BuyGas. + senderBalance := stateDB.GetBalance(sender).ToBig() - // Include cast address balance for unassociated addresses (matches V2 PreprocessDecorator) + // Include the derived Sei address balance for unassociated addresses (matches V2 PreprocessDecorator). if !isAssociated { - castAddr := sdk.AccAddress(sender[:]) - castBalance := app.GigaEvmKeeper.GetBalance(ctx, castAddr) - senderBalance = new(big.Int).Add(senderBalance, castBalance) + seiEVMAddr := common.BytesToAddress(seiAddr) + if seiEVMAddr != sender { + seiBalance := stateDB.GetBalance(seiEVMAddr).ToBig() + senderBalance = new(big.Int).Add(senderBalance, seiBalance) + } } if senderBalance.Cmp(balanceCheck) < 0 { diff --git a/giga/tests/giga_mock_balances_test.go b/giga/tests/giga_mock_balances_test.go new file mode 100644 index 0000000000..76dbdafe00 --- /dev/null +++ b/giga/tests/giga_mock_balances_test.go @@ -0,0 +1,32 @@ +//go:build mock_balances + +package giga_test + +import ( + "math/big" + "testing" + "time" + + "github.com/sei-protocol/sei-chain/occ_tests/utils" + "github.com/stretchr/testify/require" +) + +func TestGigaMockBalancesValidationUsesDBImpl(t *testing.T) { + blockTime := time.Now() + accts := utils.NewTestAccounts(3) + signer := utils.NewSigner() + recipient := utils.NewSigner() + + gigaCtx := NewGigaTestContext(t, accts, blockTime, 1, ModeGigaSequential) + gigaCtx.TestApp.GigaEvmKeeper.SetAddressMapping(gigaCtx.Ctx, signer.AccountAddress, signer.EvmAddress) + + to := recipient.EvmAddress + value := big.NewInt(1_000_000_000_000_000_000) + fee := big.NewInt(100000000000) + tx := createCustomEVMTx(t, gigaCtx, signer, &to, value, 21000, fee, fee, 0) + + _, results, err := RunBlock(t, gigaCtx, [][]byte{tx}) + require.NoError(t, err) + require.Len(t, results, 1) + require.Equal(t, uint32(0), results[0].Code, results[0].Log) +}