Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas refunds use block gas instead of transaction gas, leading to incorrect refund amounts #45

Open
howlbot-integration bot opened this issue Nov 28, 2024 · 6 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-04 primary issue Highest quality submission among a set of duplicates 🤖_12_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue sufficient quality report This report is of sufficient quality

Comments

@howlbot-integration
Copy link

Lines of code

https://github.com/code-423n4/2024-11-nibiru/blob/84054a4f00fdfefaa8e5849c53eb66851a762319/app/evmante/evmante_gas_consume.go#L100-L105

Vulnerability details

Finding description and impact

There is a mismatch between how gas fees are deducted and refunded in the EVM implementation:

  1. In evmante_gas_consume.go, gas fees are deducted upfront based on each transaction's individual gas limit
  2. However, the refund calculation in msg_server.go uses the cumulative block gas usage to determine refunds for individual transactions

This mismatch means users will receive incorrect (lower) refunds than they should. The gas refund should be based on the difference between a transaction's gas limit (what was charged) and its actual gas usage (what was consumed), not the block's total gas usage.

The impact is that users will lose funds as they receive smaller refunds than they should. This becomes especially problematic when multiple transactions are included in a block, as the cumulative block gas increases with each transaction, reducing refunds for subsequent transactions.

Proof of Concept

The issue stems from two pieces of code:

  1. Gas fees are deducted in evmante_gas_consume.go based on transaction gas limit:
// https://github.com/code-423n4/2024-11-nibiru/blob/84054a4f00fdfefaa8e5849c53eb66851a762319/app/evmante/evmante_gas_consume.go#L100-L105
		fees, err := keeper.VerifyFee(
			txData,
			evm.EVMBankDenom,
			baseFeeMicronibiPerGas,
			ctx.IsCheckTx(),
		)

Where VerifyFee returns the fee based on the transaction gas limit:

// https://github.com/code-423n4/2024-11-nibiru/blob/84054a4f00fdfefaa8e5849c53eb66851a762319/x/evm/keeper/gas_fees.go#L194-L200
	feeAmtMicronibi := evm.WeiToNative(txData.EffectiveFeeWei(baseFeeWei))
	if feeAmtMicronibi.Sign() == 0 {
		// zero fee, no need to deduct
		return sdk.Coins{{Denom: denom, Amount: sdkmath.ZeroInt()}}, nil
	}

	return sdk.Coins{{Denom: denom, Amount: sdkmath.NewIntFromBigInt(feeAmtMicronibi)}}, nil
  1. But refunds in msg_server.go are calculated using block gas:
// https://github.com/code-423n4/2024-11-nibiru/blob/84054a4f00fdfefaa8e5849c53eb66851a762319/x/evm/keeper/msg_server.go#L87-L93
blockGasUsed, err := k.AddToBlockGasUsed(ctx, evmResp.GasUsed)
if err != nil {
    return nil, errors.Wrap(err, "EthereumTx: error adding transient gas used to block")
}

refundGas := uint64(0)
if evmMsg.Gas() > blockGasUsed {
    refundGas = evmMsg.Gas() - blockGasUsed
}

To demonstrate the impact, consider this scenario:

  1. Transaction A has gas limit 100,000 and uses 50,000 gas
  2. Transaction B has gas limit 100,000 and uses 40,000 gas
  3. When calculating the refund for transaction B:
    • It should receive: 100,000 - 40,000 = 60,000 gas refund
    • But actually receives: 100,000 - (50,000 + 40,000) = 10,000 gas refund
    • The user loses refund for 50,000 gas

Recommended mitigation steps

The refund calculation should be based on each transaction's individual gas usage rather than the block gas. Modify the refund logic in msg_server.go:

// Before
blockGasUsed, err := k.AddToBlockGasUsed(ctx, evmResp.GasUsed)
refundGas := uint64(0)
if evmMsg.Gas() > blockGasUsed {
    refundGas = evmMsg.Gas() - blockGasUsed
}

// After
refundGas := uint64(0)
if evmMsg.Gas() > evmResp.GasUsed {
    refundGas = evmMsg.Gas() - evmResp.GasUsed
}
blockGasUsed, err := k.AddToBlockGasUsed(ctx, evmResp.GasUsed)

This ensures that each transaction's refund is calculated based on its own gas limit and usage, independent of other transactions in the block.

@howlbot-integration howlbot-integration bot added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value 🤖_12_group AI based duplicate group recommendation bug Something isn't working primary issue Highest quality submission among a set of duplicates sufficient quality report This report is of sufficient quality labels Nov 28, 2024
howlbot-integration bot added a commit that referenced this issue Nov 28, 2024
@c4-judge
Copy link

berndartmueller marked the issue as selected for report

@c4-judge c4-judge added selected for report This submission will be included/highlighted in the audit report satisfactory satisfies C4 submission criteria; eligible for awards labels Dec 16, 2024
@c4-judge
Copy link

berndartmueller marked the issue as satisfactory

@k-yang k-yang added the sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") label Jan 4, 2025
@rodiontr
Copy link

@berndartmueller I believe this should be of high severity as the issue deals with refunds and therefore losing of funds. There are several DOS-related issues marked as high but this one with the actual funds losing is not

@berndartmueller
Copy link
Member

@berndartmueller I believe this should be of high severity as the issue deals with refunds and therefore losing of funds. There are several DOS-related issues marked as high but this one with the actual funds losing is not

Sticking with Medium as this affects individual users, users who batch multiple EVM tx's within a single Cosmos SDK tx. And batch EVM messages are not that common currently. Thus, I think Medium is justified.

@c4-sponsor
Copy link

@Unique-Divine Sponsors are not allowed to close, reopen, or assign issues or pull requests.

@C4-Staff C4-Staff added the M-04 label Jan 17, 2025
@k-yang k-yang added sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue and removed sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") labels Jan 28, 2025
@k-yang
Copy link

k-yang commented Jan 28, 2025

Please see my comment at #46 (comment) for why I changed it to sponsor disputed.

BlockGasUsed was actually a terrible name for the gas tracker variable. It's actually the cumulative amount of gas used in the TX when multiple EVM msgs are bundled in it. It gets reset between TXs by the evm ante handler.

Since that's the case, the gas refunded here is correct. The blockGasUsed variable is actually the total amount of gas used by the entire TXs, summing up all the individually bundled EVM msgs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-04 primary issue Highest quality submission among a set of duplicates 🤖_12_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

6 participants