DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Incorrect price validation

Summary

There is an incorrect calculation in the KeeperProxy.sol contract (Line 155) within the _validatePrice() function, which checks market token prices against a Chainlink data feed before running the run()/runNextAction() function on the PerpetualVault. The way token decimals are handled leads to incorrect price validation, especially for the supported market tokens.

Vulnerability Details

The _validatePrice() function make an internal call to _check() (Root Problem) which checks the price difference between given price and the Chainlink price.

2025-02-gamma/contracts/KeeperProxy.sol at main · CodeHawks-Contests/2025-02-gamma

uint256 decimals = 30 - IERC20Meta(token).decimals();
price = price / 10 ** (decimals - 8); // Chainlink price decimals is always 8.

The price validation logic uses the formula price = price / 10 ** (decimals - 8);, where decimals is calculated as 30 - IERC20Meta(token).decimals().


This formula is wrong because it doesn’t handle tokens with fewer than 8 decimals, like USDC (6 decimals), properly:

If decimals - 8 results in a very large exponent (e.g., 10^16 for USDC), price will become zero due to Solidity’s integer division truncation.

2025-02-gamma/contracts/KeeperProxy.sol at main · CodeHawks-Contests/2025-02-gamma

The _absDiff function helps calculate the absolute difference between the two prices but doesn't help with issues in decimal handling as it will always return a false positve.

Impact

  • This would cause a false positive validation failure and block valid transactions.

Price checks will fail, allowing incorrect price offsets and miscalculations.

Recommendations

Revise the formula to dynamically account for token decimals based on actual decimals of each token and use SafeMath.

uint256 scale = 10 ** (18 - tokenDecimals);
price = price * scale / 10**8; // Use the price with Chainlink's 8 decimals
Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

invalid_prices_decimals

GMX github documentation: “Prices stored within the Oracle contract represent the price of one unit of the token using a value with 30 decimals of precision. Representing the prices in this way allows for conversions between token amounts and fiat values to be simplified, e.g. to calculate the fiat value of a given number of tokens the calculation would just be: token amount * oracle price, to calculate the token amount for a fiat value it would be: fiat value / oracle price.” Sponsor confirmed the keeper does the same, so price decimals change in function of the token, to be sure the above rule is true. Example for USDC (6 decimals): Prices will have 24 decimals → 1e6 * 1e24 = 1e30. Just a reminder for some submissions: shortToken == collateralTokens, so the decimals is 1e24 for shortToken prices.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!