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

When reverting a cross chain tx with ERC20/native token as coinType, gas will always be underpaid due to inconsistent handling of median gasPrice #516

Open
c4-bot-10 opened this issue Dec 18, 2023 · 8 comments
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue edited-by-warden grade-b Q-06 QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality

Comments

@c4-bot-10
Copy link
Contributor

c4-bot-10 commented Dec 18, 2023

Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/gas_payment.go#L151
https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/gas_payment.go#L106
https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/gas_payment.go#L285

Vulnerability details

Impact

Median gas price is inconsistently handled in gas_payment.go. For the same external chain, a sender will be charged twice as much median gas price if cointType is zeta, while a sender will be charged the exact median gas price if cointType is native gas coin or ERC20.

Proof of Concept

In gas_payment.go, outboundtx gas payment is calculated based on gasLimit and gas price. gas price is based on median gas price of the external chain. However, gas price is inconsistenly handled between different coinTypes.

When coinType is zetacoin, the gas price is fetched in PayGasInZetaAndUpdateCctx(). It gets gasPrice for chainID through k.GetMedianGasPriceInUint(). The resulting gasPrice is then doubled through gasPrice = gasPrice.MulUint64(2). This gasPrice is then used to calculate actual gas token balance to charge.

However, when coinType is ERC20 token or native gas token, gasPrice for chainId is fetched through k.ChainGasParams(ctx, chainID), which under the hood calls the same GetMedianGasPriceInUint() that directly returns gasPrice. However, gasPrice is then directly used to be multiplied by gasLimit without doubling the price as in zetacoin flow. For the same chainId, gasPrice is inconsistently priced. This results in gas to be underpaid when the crosschain tx coinType is ERC20 token or native gas token.

//x/crosschain/keeper/gas_payment.go
func (k Keeper) PayGasInZetaAndUpdateCctx(
	ctx sdk.Context,
	chainID int64,
	cctx *types.CrossChainTx,
	zetaBurnt math.Uint,
	noEthereumTxEvent bool,
) error {
...
	// get the gas price
	gasPrice, isFound := k.GetMedianGasPriceInUint(ctx, chainID)
...
        //@audit gas price is doubled from median gas price of chainId when cointType is zeta 
|>	gasPrice = gasPrice.MulUint64(2) // overpays gas price by 2x

(https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/gas_payment.go#L285)

//x/crosschain/keeper/gas_payment.go
func (k Keeper) PayGasInERC20AndUpdateCctx(
	ctx sdk.Context,
	chainID int64,
	cctx *types.CrossChainTx,
	inputAmount math.Uint,
	noEthereumTxEvent bool,
) error {
...
	// get gas params
        //@audit When cointype is erc20 token, ChainGasParams() performs the same GetMedianGasPriceInUint() to return median gas price for chainId 
|>	gasZRC20, gasLimit, gasPrice, protocolFlatFee, err := k.ChainGasParams(ctx, chainID)
...
	outTxGasFee := gasLimit.Mul(gasPrice).Add(protocolFlatFee)

(https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/gas_payment.go#L147)

//x/crosschain/keeper/gas_payment.go
func (k Keeper) ChainGasParams(
	ctx sdk.Context,
	chainID int64,
) (gasZRC20 ethcommon.Address, gasLimit, gasPrice, protocolFee math.Uint, err error) {
...
        //@audit-info ChainGasParams get the same median price as it also calls GetMedianGasPriceInUint()
|>	gasPrice, isFound := k.GetMedianGasPriceInUint(ctx, chainID)
...

(https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/gas_payment.go#L75)

Same median gas price is fetched for target chainId, however, only when the cctx coinType is zeta coin, the fetched price will be doubled. When the coinType is erc20 or gas native token, gas will be underpaid.

Tools Used

Manual review

Recommended Mitigation Steps

Consider unifying the gasPrice handling between three different coin types.

Assessed type

Error

@c4-bot-10 c4-bot-10 added 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 labels Dec 18, 2023
c4-bot-10 added a commit that referenced this issue Dec 18, 2023
@c4-bot-8 c4-bot-8 changed the title When reverting a cross chain tx with ERC20 as coinType, gas will always be underpaid due to inconsistent gas calculation. When reverting a cross chain tx with ERC20/native token as coinType, gas will always be underpaid due to inconsistent handling of median gasPrice Dec 18, 2023
@c4-pre-sort
Copy link

DadeKuma marked the issue as duplicate of #393

@c4-pre-sort
Copy link

DadeKuma marked the issue as sufficient quality report

@c4-pre-sort c4-pre-sort added the sufficient quality report This report is of sufficient quality label Dec 21, 2023
@0xean
Copy link

0xean commented Jan 7, 2024

I think this is a separate issue from #393 ( cc @DadeKuma ) - but also not sure it really qualifies as M either. The logic is not consistent, but the impact (besides some transactions having arbitrarily 2x the gas) isn't well captured by the Warden.

@c4-judge
Copy link

c4-judge commented Jan 7, 2024

0xean marked the issue as not a duplicate

@c4-judge c4-judge reopened this Jan 7, 2024
@0xean
Copy link

0xean commented Jan 7, 2024

@c4-sponsor - care to comment on this one?

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

lumtis (sponsor) confirmed

@c4-judge c4-judge added downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax and removed 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Jan 10, 2024
@c4-judge
Copy link

0xean changed the severity to QA (Quality Assurance)

@c4-judge
Copy link

0xean marked the issue as grade-b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue edited-by-warden grade-b Q-06 QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

7 participants