// evm sometimes return 0 gasRemaining, but it's not an out of gas error.
if gasRemaining == 0 && err != nil && err != vm.ErrOutOfGas {
	return nil, common.Address{}, nil, types.ErrEVMCreateFailed.Wrap(err.Error())
}
diff --git a/x/evm/contracts/counter/Counter.sol b/x/evm/contracts/counter/Counter.sol
index 2c5166e..6659e79 100644
--- a/x/evm/contracts/counter/Counter.sol
+++ b/x/evm/contracts/counter/Counter.sol
@@ -23,6 +23,27 @@ contract Counter is IIBCAsyncCallback {
         increase_for_fuzz(num - 1);
     }

+    function triggerStackOverflow() internal {
+        // Local variables to fill up the stack
+        uint256 a1 = 1;
+        uint256 a2 = 2;
+        uint256 a3 = 3;
+        uint256 a4 = 4;
+        uint256 a5 = 5;
+
+        // Recursive call that will overflow the stack
+        triggerStackOverflow();
+
+        // This line will never be reached
+        count += a1 + a2 + a3 + a4 + a5;
+    }
+
+    function consumeGas(uint256 iterations) internal {
+        for (uint256 i = 0; i < iterations; i++) {
+            count++;
+        }
+    }
+
     function increase() public payable {
         count++;
         emit increased(count - 1, count);
@@ -59,7 +80,7 @@ contract Counter is IIBCAsyncCallback {
         string memory exec_msg,
         bool allow_failure,
         uint64 callback_id
-    ) external {
+    ) public {
         COSMOS_CONTRACT.execute_cosmos_with_options(
             exec_msg,
             ICosmos.Options(allow_failure, callback_id)
@@ -77,14 +98,13 @@ contract Counter is IIBCAsyncCallback {
     function recursive(uint64 n) public {
         emit recursive_called(n);

-        if (n == 0) {
-            return;
-        }
+        execute_cosmos_with_options(_recursive(n), true, 0); // dispatches an EVM call to `nested()`, allows call to fail, no callback
+    }

-        COSMOS_CONTRACT.execute_cosmos(_recursive(n));
+    function nested() external {
+        consumeGas(1_000_000);

-        // to test branching
-        COSMOS_CONTRACT.execute_cosmos(_recursive(n));
+        triggerStackOverflow();
     }

     function _recursive(uint64 n) internal returns (string memory message) {
@@ -99,7 +119,7 @@ contract Counter is IIBCAsyncCallback {
                 '",',
                 '"input": "',
                 Strings.toHexString(
-                    abi.encodePacked(this.recursive.selector, abi.encode(n - 1))
+                    abi.encodePacked(this.nested.selector)
                 ),
                 '",',
                 '"value": "0",',
func Test_StackOverflowNoGasCharged(t *testing.T) {
	ctx, input := createDefaultTestInput(t)
	_, _, addr := keyPubAddr()

	counterBz, err := hexutil.Decode(counter.CounterBin)
	require.NoError(t, err)

	// deploy counter contract
	caller := common.BytesToAddress(addr.Bytes())
	retBz, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz, nil, nil)
	require.NoError(t, err)
	require.NotEmpty(t, retBz)
	require.Len(t, contractAddr, 20)

	// call recursive function
	parsed, err := counter.CounterMetaData.GetAbi()
	require.NoError(t, err)

	inputBz, err := parsed.Pack("recursive", uint64(1))
	require.NoError(t, err)

	gasBefore := ctx.GasMeter().GasConsumed()

	_, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz, nil, nil)

	gasUsed := ctx.GasMeter().GasConsumed() - gasBefore

	require.NoError(t, err)
	require.Equal(t, 1, len(logs))
	require.LessOrEqual(t, gasUsed, uint64(100_000))
}
