Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Follow the [migration document](docs/migrations/v0.5.x_to_v0.6.0.md) for upgrade

### BUG FIXES

- Fix undercharged internal EVM execution in `CallEVMWithData` by (1) bounding the message `GasLimit` to the caller-provided `gasCap` when set (`min(gasCap, DefaultGasCap)`) instead of always using `DefaultGasCap`, and (2) charging the SDK gas meter for the actual pre-refund work (`MaxUsedGas`) rather than the post-refund `GasUsed` on non-precompile calls, preventing a refund-maximizing contract from forcing repeatable, undercharged internal EVM compute (e.g. via the CosmWasm ERC20 query bindings).
- Fix EVM fee-abstraction gas refund to compute the refund against the full transaction gas (`gasUsed + leftoverGas`) instead of `gasUsed`, bounding the refund by the paid fee and preventing the fee collector from being drained by high gas limit transactions.
- [\#15](https://github.com/KiiChain/evm/pull/15) Fix distribution precompile 32-byte withdraw address inflating native supply by skipping non-20-byte accounts when mirroring balance changes to the StateDB.

Expand Down
24 changes: 22 additions & 2 deletions x/vm/keeper/call_evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,22 @@ func (k Keeper) CallEVMWithData(ctx sdk.Context, stateDB *statedb.StateDB, from
return nil, err
}

// Bound the EVM gas limit by the caller-provided gasCap when set, falling
// back to DefaultGasCap. This prevents callers (e.g. CosmWasm query bindings)
// from triggering EVM execution larger than their remaining gas budget.
gasLimit := config.DefaultGasCap
if gasCap != nil && gasCap.IsUint64() {
if capped := gasCap.Uint64(); capped < gasLimit {
gasLimit = capped
}
}

msg := core.Message{
From: from,
To: contract,
Nonce: nonce,
Value: big.NewInt(0),
GasLimit: config.DefaultGasCap,
GasLimit: gasLimit,
GasPrice: big.NewInt(0),
GasTipCap: big.NewInt(0),
GasFeeCap: big.NewInt(0),
Expand All @@ -68,7 +78,17 @@ func (k Keeper) CallEVMWithData(ctx sdk.Context, stateDB *statedb.StateDB, from
return res, errorsmod.Wrap(types.ErrVMExecution, res.VmError)
}

ctx.GasMeter().ConsumeGas(res.GasUsed, "apply evm message")
// Charge the SDK gas meter for the actual pre-refund EVM work (MaxUsedGas)
// rather than the post-refund GasUsed. Internal calls run with a full refund
// and no minimum-gas floor, so GasUsed can fall far below the real compute
// performed by validators; billing MaxUsedGas removes that undercharge.
// Precompile sub-calls keep their existing accounting.
chargedGas := res.GasUsed
if !callFromPrecompile && res.MaxUsedGas > chargedGas {
chargedGas = res.MaxUsedGas
}

ctx.GasMeter().ConsumeGas(chargedGas, "apply evm message")

return res, nil
}
Loading