diff --git a/libs/cosmos-sdk/baseapp/abci.go b/libs/cosmos-sdk/baseapp/abci.go
index 9bbd4ba527..f8a2ea29b2 100644
--- a/libs/cosmos-sdk/baseapp/abci.go
+++ b/libs/cosmos-sdk/baseapp/abci.go
@@ -11,9 +11,6 @@ import (
 	"syscall"
 	"time"
 
-	"github.com/spf13/viper"
-	"github.com/tendermint/go-amino"
-
 	"github.com/okex/exchain/app/rpc/simulator"
 	"github.com/okex/exchain/libs/cosmos-sdk/codec"
 	"github.com/okex/exchain/libs/cosmos-sdk/store/mpt"
@@ -24,7 +21,10 @@ import (
 	"github.com/okex/exchain/libs/system/trace"
 	"github.com/okex/exchain/libs/system/trace/persist"
 	abci "github.com/okex/exchain/libs/tendermint/abci/types"
+	cfg "github.com/okex/exchain/libs/tendermint/config"
 	tmtypes "github.com/okex/exchain/libs/tendermint/types"
+	"github.com/spf13/viper"
+	"github.com/tendermint/go-amino"
 )
 
 // InitChain implements the ABCI interface. It runs the initialization logic
@@ -410,7 +410,31 @@ func (app *BaseApp) Query(req abci.RequestQuery) abci.ResponseQuery {
 		return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path"))
 	}
 }
-func handleSimulate(app *BaseApp, path []string, height int64, txBytes []byte, overrideBytes []byte) abci.ResponseQuery {
+
+func handleSimulateWithBuffer(app *BaseApp, path []string, height int64, txBytes []byte, overrideBytes []byte) abci.ResponseQuery {
+	simRes, shouldAddBuffer, err := handleSimulate(app, path, height, txBytes, overrideBytes)
+	if err != nil {
+		return sdkerrors.QueryResult(err)
+	}
+	if shouldAddBuffer {
+		buffer := cfg.DynamicConfig.GetGasLimitBuffer()
+		gasUsed := simRes.GasUsed
+		gasUsed += gasUsed * buffer / 100
+		if gasUsed > SimulationGasLimit {
+			gasUsed = SimulationGasLimit
+		}
+		simRes.GasUsed = gasUsed
+	}
+
+	return abci.ResponseQuery{
+		Codespace: sdkerrors.RootCodespace,
+		Height:    height,
+		Value:     codec.Cdc.MustMarshalBinaryBare(simRes),
+	}
+
+}
+
+func handleSimulate(app *BaseApp, path []string, height int64, txBytes []byte, overrideBytes []byte) (sdk.SimulationResponse, bool, error) {
 	// if path contains address, it means 'eth_estimateGas' the sender
 	hasExtraPaths := len(path) > 2
 	var from string
@@ -430,9 +454,16 @@ func handleSimulate(app *BaseApp, path []string, height int64, txBytes []byte, o
 	if tx == nil {
 		tx, err = app.txDecoder(txBytes)
 		if err != nil {
-			return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx"))
+			return sdk.SimulationResponse{}, false, sdkerrors.Wrap(err, "failed to decode tx")
 		}
 	}
+	// if path contains mempool, it means to enable MaxGasUsedPerBlock
+	// return the actual gasUsed even though simulate tx failed
+	isMempoolSim := hasExtraPaths && path[2] == "mempool"
+	var shouldAddBuffer bool
+	if !isMempoolSim && tx.GetType() != types.EvmTxType {
+		shouldAddBuffer = true
+	}
 
 	msgs := tx.GetMsgs()
 
@@ -445,46 +476,32 @@ func handleSimulate(app *BaseApp, path []string, height int64, txBytes []byte, o
 			}
 		}
 		if isPureWasm {
-			return handleSimulateWasm(height, txBytes, msgs)
+			res, err := handleSimulateWasm(height, txBytes, msgs)
+			return res, shouldAddBuffer, err
 		}
 	}
 	gInfo, res, err := app.Simulate(txBytes, tx, height, overrideBytes, from)
-
-	// if path contains mempool, it means to enable MaxGasUsedPerBlock
-	// return the actual gasUsed even though simulate tx failed
-	isMempoolSim := hasExtraPaths && path[2] == "mempool"
 	if err != nil && !isMempoolSim {
-		return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx"))
+		return sdk.SimulationResponse{}, false, sdkerrors.Wrap(err, "failed to simulate tx")
 	}
 
-	simRes := sdk.SimulationResponse{
+	return sdk.SimulationResponse{
 		GasInfo: gInfo,
 		Result:  res,
-	}
-
-	return abci.ResponseQuery{
-		Codespace: sdkerrors.RootCodespace,
-		Height:    height,
-		Value:     codec.Cdc.MustMarshalBinaryBare(simRes),
-	}
+	}, shouldAddBuffer, nil
 }
 
-func handleSimulateWasm(height int64, txBytes []byte, msgs []sdk.Msg) (abciRes abci.ResponseQuery) {
+func handleSimulateWasm(height int64, txBytes []byte, msgs []sdk.Msg) (simRes sdk.SimulationResponse, err error) {
 	wasmSimulator := simulator.NewWasmSimulator()
 	defer wasmSimulator.Release()
 	defer func() {
 		if r := recover(); r != nil {
 			gasMeter := wasmSimulator.Context().GasMeter()
-			simRes := sdk.SimulationResponse{
+			simRes = sdk.SimulationResponse{
 				GasInfo: sdk.GasInfo{
 					GasUsed: gasMeter.GasConsumed(),
 				},
 			}
-			abciRes = abci.ResponseQuery{
-				Codespace: sdkerrors.RootCodespace,
-				Height:    height,
-				Value:     codec.Cdc.MustMarshalBinaryBare(simRes),
-			}
 		}
 	}()
 
@@ -492,28 +509,23 @@ func handleSimulateWasm(height int64, txBytes []byte, msgs []sdk.Msg) (abciRes a
 	wasmSimulator.Context().GasMeter().ConsumeGas(uint64(10*len(txBytes)), "tx size cost")
 	res, err := wasmSimulator.Simulate(msgs)
 	if err != nil {
-		return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate wasm tx"))
+		return sdk.SimulationResponse{}, sdkerrors.Wrap(err, "failed to simulate wasm tx")
 	}
 
 	gasMeter := wasmSimulator.Context().GasMeter()
-	simRes := sdk.SimulationResponse{
+	return sdk.SimulationResponse{
 		GasInfo: sdk.GasInfo{
 			GasUsed: gasMeter.GasConsumed(),
 		},
 		Result: res,
-	}
-	return abci.ResponseQuery{
-		Codespace: sdkerrors.RootCodespace,
-		Height:    height,
-		Value:     codec.Cdc.MustMarshalBinaryBare(simRes),
-	}
+	}, nil
 }
 
 func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
 	if len(path) >= 2 {
 		switch path[1] {
 		case "simulate":
-			return handleSimulate(app, path, req.Height, req.Data, nil)
+			return handleSimulateWithBuffer(app, path, req.Height, req.Data, nil)
 
 		case "simulateWithOverrides":
 			queryBytes := req.Data
@@ -521,7 +533,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res
 			if err := json.Unmarshal(queryBytes, &queryData); err != nil {
 				return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode simulateOverrideData"))
 			}
-			return handleSimulate(app, path, req.Height, queryData.TxBytes, queryData.OverridesBytes)
+			return handleSimulateWithBuffer(app, path, req.Height, queryData.TxBytes, queryData.OverridesBytes)
 
 		case "trace":
 			var queryParam sdk.QueryTraceTx
diff --git a/libs/tendermint/config/dynamic_config_okchain.go b/libs/tendermint/config/dynamic_config_okchain.go
index 288048994d..c69bea78a7 100644
--- a/libs/tendermint/config/dynamic_config_okchain.go
+++ b/libs/tendermint/config/dynamic_config_okchain.go
@@ -33,6 +33,7 @@ type IDynamicConfig interface {
 	GetDynamicGpMode() int
 	GetDynamicGpMaxTxNum() int64
 	GetDynamicGpMaxGasUsed() int64
+	GetGasLimitBuffer() uint64
 }
 
 var DynamicConfig IDynamicConfig = MockDynamicConfig{}
@@ -185,3 +186,7 @@ func (d *MockDynamicConfig) SetDynamicGpMaxGasUsed(value int64) {
 func (d MockDynamicConfig) GetDynamicGpMaxGasUsed() int64 {
 	return d.dynamicGpMaxGasUsed
 }
+
+func (d MockDynamicConfig) GetGasLimitBuffer() uint64 {
+	return 0
+}