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

Broken functionality in GMXProxy can lead to DOS

Summary

There is a fucntion GmxProxy::getMarketPrices which supposed to retriving the prices through GMX::Oracle is not handled or used properly which could lead to DOS the whole protocol.

Vulnerability Details

// GmxProxy::getMarketPrices
address oracle = IOrderHandler(orderHandler).oracle();
prices.indexTokenPrice = IOracle(oracle).getPrimaryPrice(
marketInfo.indexToken
);
// https://github.com/CodeHawks-Contests/2025-02-gamma/blob/84b9da452fc84762378481fa39b4087b10bab5e0/contracts/GmxProxy.sol#L128

So this function is retriving the prices through the GMX oracle on chain to use it later. So this function first retrieving the retriving oracle address from the orderHandler. To fetch the price from direcly Oracle (`0xb8fc96d7a413C462F611A7aC0C912c2FE26EAbC4`) but the price is not updated in the Oracle so it always returns 0. (As the price is not updated).

There is actually 2 orderHandler address which used in protocol, both result to same oracle address.

OrderHandler (According to test) contracts/test/PerpetualVaultTest

address orderHandler = address(0xe68CAAACdf6439628DFD2fe624847602991A31eB);
returns oracle() => 0xb8fc96d7a413C462F611A7aC0C912c2FE26EAbC4
// https://github.com/CodeHawks-Contests/2025-02-gamma/blob/84b9da452fc84762378481fa39b4087b10bab5e0/test/PerpetualVault.t.sol#L60C1-L61C1

OrderHandler (According to scripts) contracts/scripts/deploy/1_deployGmxProxy.js

"0xB0Fc2a48b873da40e7bc25658e5E6137616AC2Ee", // GMX OrderHandler
returns oracle() => 0xb8fc96d7a413C462F611A7aC0C912c2FE26EAbC4
// https://github.com/CodeHawks-Contests/2025-02-gamma/blob/84b9da452fc84762378481fa39b4087b10bab5e0/scripts/deploy/1_deployGmxProxy.js#L15C8-L15C50

So as this return 0, this function has a check actually which revert with the error EmptyPrimaryPrice(token) always,which hasn't handelled or checked properly in GMXProxy::getMarketPrices

// GMX::Oracle::getPrimaryPrice()
function getPrimaryPrice(address token) external view returns (Price.Props memory) {
if (token == address(0)) { return Price.Props(0, 0); }
Price.Props memory price = primaryPrices[token];
if (price.isEmpty()) {
revert Errors.EmptyPrimaryPrice(token);
}

Impact

It always going to revert with Error whenever protocol try to open position which basically make it DOS.
So the work flow opening the position is

  1. Gamma Keeper use run funtion to create a request in GMX perpertual to open a position

  2. Once the order is executed by GMX keeper, GMX is going to call back to GMXProxy::afterOrderExecution

  3. This function use GMXProxy::getMarketPrices to retrive the price.

  4. As explained above this function is broken so it's always revert

// GMXProxy::afterOrderExecution
function afterOrderExecution(
bytes32 requestKey,
Order.Props memory order,
EventLogData memory eventData
) external override validCallback(requestKey, order) {
console.log("in");
bytes32 positionKey = keccak256(
abi.encode(
address(this),
order.addresses.market,
order.addresses.initialCollateralToken,
order.flags.isLong
)
);
- MarketPrices memory prices = getMarketPrices(order.addresses.market);

Tools Used

Manual Review

POC

Copy this function in test/PerpetualVaultTest

function testBrokenFunction() public {
address gmxProxy = address(PerpetualVault(vault).gmxProxy());
bytes32 randomKey = keccak256(abi.encode("random"));
Order.Props memory order;
order.addresses.account = gmxProxy;
order.addresses.market = PerpetualVault(vault).market();
EventLogData memory eventData;
address orderHandler = GmxProxy(payable(gmxProxy)).orderHandler();
vm.prank(orderHandler);
GmxProxy(payable(gmxProxy)).afterOrderExecution(randomKey, order, eventData);
}

Output:

Failing tests:
Encountered 1 failing test in test/PerpetualVault.t.sol:PerpetualVaultTest
[FAIL: custom error 0xcd64a025: 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1] testBrokenFunction() (gas: 120310)
// same thing
└─$ cast sig "EmptyPrimaryPrice(address)"
0xcd64a025 (error from `GMX::Oracle::getPrimaryPrice()`

Revert with the same error

Recommendations

Use another way to fetch prices as this is not working

Updates

Lead Judging Commences

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

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

Support

FAQs

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

Give us feedback!