Guardian's review of Synthetics Updates, November 2025 for GMX, published November 2025. The report records 25 findings across 2 review rounds, including 2 high and 4 medium.
- Published
- Review window
- October 14 to 25, 2025
- Rounds
- Main Review, Remediation Review
- Language
- Solidity
- Chains
- Arbitrum, Avalanche
- Sector
- Perpetuals
- 0 Critical
- 2 High
- 4 Medium
- 17 Low
- 2 Informational
Scope
Findings 25
Main Review
13 findings · October 14 to 25, 2025-
H-01 High Virtual Inventory Does Not Track Correctly Logical Error Resolved
Description
The Virtual Inventory is still maintained based upon USD values in the
MarketUtils.applyDeltaToOpenInterestfunction instead of being based on size in token values and factoring in the current token price.However in the
getPriceImpactUsdfunction theparams.usdDeltain memory is updated to reflect the size in token delta valued at the corresponding index token price when theUSE_OPEN_INTEREST_IN_TOKENS_FOR_BALANCEvalue is true.This will result in reverts and inaccurate price impact calculations throughout the exchange.
Recommendation
The Virtual Inventory must now be tracked in token sizes and factor the current index price in it’s logic. This poses a sensitive migration from the existing values stored for live virtual inventories.
-
H-02 High Funding Is Broken Due To Asymmetry Logical Error Resolved
Description
The update of funding relying on the current notional value of open interest now requires a mirroring update to the distribution units of funding fees. Currently the funding fee amount charged is not in agreement with the funding that is computed by the funding algorithm due to asymmetry in the way that the per unit funding is distributed and the way it is collected.
- Index token price is $2
- $200 OI Cost Long, token size 100
- $100 OI Cost Short, token size 50
- Index token price goes to $1.50
- $150 OI Notional Long
- $75 OI Notional Short
- On the long side there is a position using the long token as collateral with 65 size in tokens and $125 in cost, and a position using the short token as collateral with 35 size in tokens and $75 in cost
- On the short side there is one position using the short token as collateral with 50 size in tokens and $100 in cost
- Funding determines that $10 is to be paid from longs to shorts
- fundingUsdForLongCollateral = $10 * 65 / 100 = $6.5
- fundingUsdForShortCollateral = $10 * 35 / 100 = $3.5
- result.fundingFeeAmountPerSizeDelta.long.longToken = $6.5 / 97.5 OI Notional = 0.0667 per Notional OI
- result.fundingFeeAmountPerSizeDelta.long.shortToken = $3.5 / 52.5 = $0.07 per Notional OI
- result.claimableFundingAmountPerSizeDelta.short.longToken = $6.5 / $75 = 0.0867 per Notional OI
- result.claimableFundingAmountPerSizeDelta.short.shortToken = $3.5 / $75 = 0.0467 per Notional OI
- However these claimable factors are not partitioned out based upon notional OI, but instead the cost OI, therefore the contracts will end up paying out more than the $10 in funding:
- result.claimableFundingAmountPerSizeDelta.short.longToken is applied per cost OI for all shorts: 0.0867 * $100 = $8.67
- result.claimableFundingAmountPerSizeDelta.short.shortToken is applied per cost OI for all shorts: 0.0467 * $100 = $4.67
- The summation of total funding received by the shorts is 8.67 + 4.67 = 13.34 which is significantly larger than the amount of funding computed
- Notice that in this calculation we have ignored the conversion back to collateral tokens for the funding per size for the sake of example
- If the funding were to be partitioned out based upon the current notional size:
- result.claimableFundingAmountPerSizeDelta.short.longToken is applied per cost OI for all shorts: 0.0867 * $75 = $6.50
- result.claimableFundingAmountPerSizeDelta.short.shortToken is applied per cost OI for all shorts: 0.0467 * $75 = $3.50
- The aggregate funding received is the expected $6.50 + $3.50 = $10
- However funding cannot be paid out this way because notional sizes change over time based on index token price, instead the funding per size should be stored in per size units of “per index sizeInToken”.
Recommendation
Refactor the funding per size logic on the distribution side and the collection side throughout GMX to use a perSizeInToken over a perSizeInCost model.
-
M-01 Medium Longs Incorrectly Share Borrowing Fees Logical Error Acknowledged
Description
The borrowing fees are attributed to positions based on their open interest contributions in position “cost” rather than their current position notional value.
This can be seen in the
MarketUtils.getBorrowingFeesfunction where the positionsizeInUsdwith the difference in thecumulativeBorrowingFactorproduces the resulting borrowing fee USD amount.However, the
sizeInUsdis not exactly what contributes to the borrowing fees charged to a side, instead it is thereservedUsd.For shorts, this
reservedUsdis the cost basis of the positions, so the borrowing fees being applied based on thesizeInUsdis correct.However for longs, the
reservedUsdis the notional value of the long open interest in tokens. As a result, the borrowing fees are not necessarily spread out amongst long positions fairly. There may be a long position that entered while prices were low and has a low “cost” but a large current notional value, and is thus reserving a larger share of the pool backing value than a position that has a higher cost but a lower notional value.The correct distribution of borrowing fees for longs would be to charge the position with the higher notional value a higher share of the borrowing fees. But in this example that position is actually charged a lower share of the borrowing fees.
Recommendation
Changing this logic may be too risky and garner too much complexity at this point. However be aware of this inexact distribution of borrowing fees on the exchange.
-
M-02 Medium Position Health Changed On Upgrade Warning Acknowledged
Description
The upgrade will change the impact values that are computed in the
isPositionLiquidatablefunction as well as the impact that would be realized upon decreasing or liquidating the position.This means the effective health of positions are changed immediately by this upgrade, and it may be the case that non-liquidatable positions could be made liquidatable or even insolvent. And currently liquidatable positions could be made healthy.
This may pose a risk to the health of markets on the exchange and if not carefully orchestrated, could cause bad debt in a GM market.
Recommendation
Ensure that there are no positions that would experience a large change in the price impact that they would receive and thus do not have a significant change in health.
-
M-03 Medium Funding Fees Are Incorrectly Distributed Logical Error Acknowledged
Description
Now that funding is determined based upon the current notional value of each side, those positions which contribute more towards the current notional value should be charged and awarded accordingly.
Currently, the charging and awarding of funding fees is based on the
sizeInUsdof the position. However consider the following scenario:- Longs have $100 total notional size
- Shorts have $50 total notional size
- Longs pay shorts $10 of funding
- Bob is a long with $60 of cost and $40 of notional size
- Alice is a long with $40 of cost and $60 of notional size
- Bob pays $6 of funding while Alice pays $4 of funding, even though Alice contributes 50% more to the current notional size
Recommendation
Consider if the funding distribution should be updated to be based upon the notional size of positions instead of the cost.
-
L-01 Low Liquidation Preference Hijacked Unexpected Behavior Resolved
Description
When a position is insolvent there is a particular order in which debts are prioritized in the
DecreasePositionCollateralUtilsfile, however now because position increase orders with only collateral can be executed even when the position is insolvent, this liquidation preference can be bypassed.This is because the funding and borrowing fees are charged to the user’s position collateral in the
processCollateralfunction on increase.The funding fees carry the highest priority on liquidation, however the borrowing fees carry a lower priority than paying the PnL. This may be unexpected as a portion of the remaining collateral from the position can now go towards the borrowing fee receiver instead of to paying down the outstanding PnL.
Recommendation
Be aware of this bypass of the liquidation preference for insolvent positions, and consider adding back a portion of the validation in the validatePosition function, such as the minimum collateral USD check to ensure that insolvent positions cannot be updated to bypass this liquidation preference.
-
L-02 Low Max Price Is Always Used Unexpected Behavior Resolved
Description
When computing the
swapPriceImpact, the USD value of each side of the pool is computed using themidPriceof the provided price.However for the position price impact as well as the funding and borrowing sum position notional calculations, the max price of the index token is used. When purely comparing sides to discern which is larger, this has no effect since both are using the max price.
But for calculations such as price impact or funding, this can create a difference as the delta in tokens is worth more in USD if the maximum price is used. If there is a spread being used for the relevant index token in the action, then this spread will have an impact on the resulting funding and impact that is charged.
Recommendation
Consider if the
midPriceshould be used, similar to how it is used in theswapPriceImpactcalculations to limit the effect of the spread on these operations. -
L-03 Low Position Health Can Decrease On Collateral Deposits Unexpected Behavior Resolved
Description
When computing the borrowing fee amount that will be charged in collateral units to the user’s collateral, the borrowing fee amount in USD is divided by the price that is stored in the Oracle contract for the execution of the order.
This price effectively determines how much a user pays for borrowing fees, and therefore if an order is executed with prices from 5 minutes ago, then it could result in the account paying more or less borrowing fees (effective) than if that order were to be executed with the current prices, or if a liquidation were to occur at the current prices.
In some cases this may allow a position to decrease their health, as measured by current prices, with the execution of an increase order that only adds a small amount of collateral and is being executed with slightly stale prices.
Recommendation
This is fine when a position is safely healthy, however it would be best to explicitly prevent a position from becoming insolvent even after an order is executed that only adds collateral, because of this edge case. Consider keeping all of the validations that occur in validatePosition for all increase orders and only optionally performing the leverage validation based on if the order has a nonzero sizeDelta or not.
-
L-04 Low Stepwise Pool Value Changes Unexpected Behavior Acknowledged
Description
The pool value may change in a stepwise fashion during this upgrade since the definition of the smaller side for borrowing fees has changed.
Consider the following scenario:
- Skip smaller side is true
- Longs have 10 pending borrowing fees in aggregate, if they were to be charged
- Shorts have 5 pending borrowing fees in aggregate, if they were to be charged
- Longs have a total “cost” of 100 USD, and a notional of $80
- Shorts have a total “cost” of 90 USD, and a notional of $110
- Before this upgrade takes place, the smaller side is shorts, and the pending fees are 5
- After this upgrade takes place, the smaller side is longs, and the pending fees are 10
This creates an immediate change in the value of the pool and thus the price of the GM tokens in the single transaction that enables the new token open interest valuation.
This may create issues for integrators who accept GM tokens as collateral, due to a stepwise reduction in value, or small arbitrage opportunities due to a stepwise increase in value.
Recommendation
Be aware of this risk when performing the upgrade.
-
L-05 Low Likely Impact Pool Dearth Warning Acknowledged
Description
In the past, it has been an invariant that the position impact pool does not pay out more than it receives paid in. With the new impact system there are few exceptions to this that are accepted, however still generally this ideal holds.
This upgrade threatens this status for live GM markets, since the pending impact that has been already computed and stored for open positions was computed using the previous impact calculations.
The new impact calculations could allow a net positive impact to be paid out upon all of the open positions when decreasing. This would leave a dearth of a lent amount on the market which does not get repaid even after all positions have closed.
Recommendation
Be aware of this risk of introducing a dearth lent amount, and be prepared to use the admin functions to reduce lent amount as needed.
-
L-06 Low Funding Is Charged Inaccurately Retroactively Unexpected Behavior Acknowledged
Description
Because the funding fees are now based upon the current notional value of each side, which factors the current market price. Whatever the price is at the time of the action that is updating the funding is, determines what the funding is that was charged over the entire period after the last funding update.
Consider the following scenario:
- At time 100 there is a funding update, price is $100
- At time 110 the price is still $100
- At time 111 there is a second funding update, price is $105
In this example, the funding is charged as if the price has been $105 for the entire period from
[100, 110].Recommendation
Be aware of this behavior, it may be fine as long as actions are frequent.
-
L-07 Low Saved Funding Factor Rate Reset Unexpected Behavior Acknowledged
Description
The
updateFundingStatefunction relies on thegetNextFundingAmountPerSizefunction to return a result object which contains thenextSavedFundingFactorPerSecondthat will be written to storage.In the case where either long or short open interest is zero, the
getNextFundingAmountPerSizefunction returns an empty result object which uses a default uint value of 0 for thenextSavedFundingFactorPerSecond.As a result, the saved funding factor is always reset to zero, no matter what its value was before the funding update.
This may allow for a minor gaming of the funding rate in an edge case where there is only one large position that is paying funding fees on the paying side. Assuming the adaptive funding rate model is enabled, and that it slowly ratchets up the funding rate over time. The single large position on the paying side may strategically close their position and re-open it so that there is a funding update where the paying side goes to zero open interest and triggers this early return in the funding flow, resetting the saved funding factor per second value.
The position would then be re-opened and the funding increase would start to occur at a slower rate until the funding factor per second was ratcheted back up to the previous value. Compared to the base scenario without closing and re-opening the position, this position on the larger OI side would pay less funding fees overall, but likely more position order related fees.
Recommendation
Consider returning the current saved funding factor per second in the early return case in the
getNextFundingAmountPerSizefunction. -
I-01 Informational Funding And Borrowing Fees Can Prevent Deposit Warning Acknowledged
Description
During the increase flow in the
processCollateralfunction the outstanding fees are deducted from thecollateralDelta.As a result, it is possible for the
collateralDeltato be negative, and in some cases where positions are in a profit to be more negative than the existing collateral for the position. These cases will result in a revert, disallowing the order even if it adds only collateral and not size to the position.Recommendation
Simply be aware that these cases can arise which prevent collateral addition for positions with high outstanding fees that are supported by profit.
Remediation Review
12 findings · October 23 to 25, 2025-
M-01 Medium Positions May Be Prevented From Closing DoS Acknowledged
Description
During the price impact computation flow the
getNextOpenInterestParamsfunction will revert if the providedparams.usdDeltavalue is greater than the long or short open interest. There is an edge case where this can be possible which prevents the last position holder from entirely closing their position. When a market has homogenous backing tokens thegetOpenInterestresult is divided by a divisor of 2, which can lead to rounding error on the order of 1 wei. Since rounding occurs in the downward direction, the resulting open interest can understate the actual open interest in the market by 1 wei. Consider the following example:- Trader A has the only long position in a market with a sizeInUsd of 10e18+1 and attempts to close it all
- The result of getOpenInterest reports: (10e18+1)/2 + (10e18+1)/2 = 10e18
- The getNextOpenInterestParams confirms that (-params.usdDelta).toUint256() > longOpenInterest => 10e18+1 > 10e18
- Results in a revert UsdDeltaExceedsLongOpenInterest
Recommendation
If the
usdDeltais 1 wei larger than the long or short open interest in thegetNextOpenInterestParamsfunction, consider assigning thenextLongOpenInterestornextShortOpenInterestto 0 to avoid reverts in this case. -
L-01 Low Lacking OI Notional Caps Validation Acknowledged
Description
In the
validateOpenInterestfunction that caps open interest within theapplyDeltaToOpenInterestfunction the open interest is validated based on cost basis. However in theapplyDeltaToOpenInterestInTokensfunction the open interest is not validated based on the tokens exposure, nor the current notional value.Recommendation
Consider if there should be validation caps on the open interest in the
applyDeltaToOpenInterestInTokensto limit open interest in two ways:- Raw token amount open interest caps
- Current value notional open interest caps
-
L-02 Low Virtual Inventory Migration Risks Warning Acknowledged
Description
The virtual inventory tracking for the size in tokens with the
getVirtualInventoryForPositionsInTokensfunction relies on thevirtualInventoryForPositionsInTokensKeykey which is not synced with the current token exposures of a market, therefore necessitating a manual syncing process.If the virtual inventory is not synced properly it would perturb the incentive to balance the index token market group sufficiently, and may end up punishing traders more than they ought to be when receiving negative impact. Furthermore, it can also result in unjust liquidations, as the price impact result is included in the formula for an account’s health.
The migration process is therefore very sensitive and must be carried out at the same time in which the tokens open interest usage is turned on. If at any point during the migration process a position is closed, opened, increased, or decreased, changing the
openInterestInTokensfor a market before theUSE_OPEN_INTEREST_IN_TOKENS_FOR_BALANCEkey is enabled, the values that seeded the virtual inventory in tokens will be incorrect.Recommendation
Ideally the migration would use a single atomic transaction onchain which computes the correct net market exposure for the virtual inventory for every group and updates the virtual inventory for tokens key storage accordingly all in the same single transaction as the
USE_OPEN_INTEREST_IN_TOKENS_FOR_BALANCEkey is enabled.This way there is no opportunity for a position change to perturb the new virtual inventory in tokens values.
Alternatively, consider pausing trading activities for a brief period while the migration is occurring.
-
L-03 Low One Way Migration Process Warning Warning Acknowledged
Description
In the
applyDeltaToOpenInterestfunction an if conditional has been added to only invoke theapplyDeltaToVirtualInventoryForPositionswhenuseOpenInterestInTokensis false.This creates a one-way door with respect to the migration process because if the virtual inventory based on the cost-basis is not being updated in lock-step with every position update that occurs, it will become out of sync.
This means once the
useOpenInterestInTokensvalue is set to true, it can never be back-stepped to false because the old cost-basis virtual inventory will be out of sync and will not correctly apply price impact for trades, and may even cause liquidations to occur when they rightfully shouldn’t.Recommendation
Consider removing the if conditional around the
applyDeltaToVirtualInventoryForPositionsfunction so that if the migration should need to be reversed, it safely can be.At a later time, once the migration is proven to be safe, the conditional can be added, or the old code removed entirely.
-
L-04 Low oracleProviderUpdatedAt Ineffective Validation Validation Acknowledged
Description
The
setOracleProviderForFeeHandlerTokenfunction the oracleProviderUpdatedAt validation is keyed based on the token and provider combination. Therefore when a new provider is used to configure for a token the cooldown validation is not triggered.The cooldown is only triggered when the same exact token and provider configuration is used again, which doesn’t add as much protection as if the key was based purely off of the token. This however might limit practical configuration use-cases.
Recommendation
Confirm that the current validation is intended and be aware that it is not as constricting as it could be.
-
L-05 Low Virtual Inventory Keys Are Allowed Base Keys Warning Acknowledged
Description
In the
Configcontract theVIRTUAL_INVENTORY_FOR_POSITIONSandVIRTUAL_INVENTORY_FOR_POSITIONS_IN_TOKENSkeys are declared as allowed base keys which can be configured by the config keeper.However this may be a mechanism through which the config keeper is able to cause liquidations, by assigning a virtual inventory value that forces the maximum allowable magnitude negative price impact to affect the overall health of positions and force many on the exchange into liquidation.
Recommendation
Consider adding guardrails on the configuration values allowed for the virtual inventory related keys since these are system accounting variables. Otherwise consider removing them as an
allowedBaseKey. -
L-06 Low Dangerous OI In Tokens Base Key Warning Acknowledged
Description
The
USE_OPEN_INTEREST_IN_TOKENS_FOR_BALANCEkey is whitelisted in theallowedBaseKeymapping, however this may serve as a mechanism for the config keeper to liquidate positions or otherwise perturb the balancing mechanism of the exchange.After the migration has taken place it is imperative that this value is not reset to false, as the previous open interest tracking may be inaccurate, especially in the case of the virtual inventory, which may lead to the incorrect liquidation of positions.
Recommendation
Consider removing this key from the Config contract shortly after performing the migration.
-
L-07 Low Positive Price Impact Capped On Cost Warning Acknowledged
Description
In the
capPositiveImpactUsdByMaxPositionImpactfunction themaxPriceImpactUsdBasedOnMaxPriceImpactFactorvalue is determined based upon the order’ssizeDeltaUsd.Therefore if an order, particularly a decrease order, has a small
sizeDeltaUsdthen the positive cap will be small. However this is not based upon the actual notional value that the order represents, which is determined by thesizeInTokens * indexPrice. After the migration is made, the sizeInUsd will also not be the metric which the price impact is based upon, creating a divergence between the capping logic and the way the price impact is computed.Therefore in some edge cases where an account has made a lot of profit or a large loss, the capping may be inaccurate for the actual Notional size that is experiencing impact.
Recommendation
Consider refactoring the
capPositiveImpactUsdByMaxPositionImpactcap validation to be based upon the notional size of the order instead of the cost delta of the order. -
L-08 Low Negative Price Impact Capped On Cost Warning Acknowledged
Description
In the
isPositionLiquidatablefunction as well as theDecreasePositionCollateralUtilsflow, negative price impact is capped based upon the order’ssizeDeltaUsdrather than the actual notional value of the order.After the migration this can cause a disconnect between the way price impact is calculated (now based on notional value) and the way it is capped (still based on cost).
Recommendation
Consider updating these negative caps in the
isPositionLiquidatablefunction as well as theDecreasePositionCollateralUtilsflow to be based upon the notional value of the order. -
L-09 Low Price Impact Pool Gaming Risk Gaming Acknowledged
Description
Because the price impact calculations are now based upon the notional value of the difference in OIs, the value that is awarded or charged to a user for price impact is determined in some part by the index token price.
When the index token price goes downwards, the notional value of a sizeInTokens diff decreases and thus decreases the amount of price impact that is awarded or charged for creating that sizeInTokens diff. When the index token price goes upwards, the notional value of a sizeInTokens diff increases and thus increases the amount of price impact that is awarded or charged for creating that sizeInTokens diff.
There may exist some strategies to gain an overall positive net price impact through this, by causing larger imbalances in a market when token price trends down, and closing those imbalances when index token price trends up — and receiving more net positive impact for doing so than was paid in negative impact upon the creation of this imbalance.
Recommendation
Be aware that impact pool gaming opportunities such as this may exist, though are not risk free. The capping of the lent amount can help to limit the impact of any such strategy if it were to be carried out.
-
L-10 Low MaxCollateralSum Decrease DoS DoS Acknowledged
Description
The system reverts now if the new
collateralSumafter applying some delta is bigger than themaxCollateralSum.This check is also performed if the delta decreased the
collateralSum. This will DoS the possibility to set themaxCollateralSumbelow the currentcollateralSumto prevent new increments and decrease it over time as in that case decreasing the collateral is DoSed too.Recommendation
Be aware that impact pool gaming opportunities such as this may exist, though are not risk free. The capping of the lent amount can help to limit the impact of any such strategy if it were to be carried out.
-
I-01 Informational Decrease Flow Always Uses Initial Margin Factor Warning Acknowledged
Description
If a increase order does only increase the collateral of a position and not it's size and therefore decreases the overall leverage of the position. Than the collateral requirements are checked using the maintenance margin factor instead of the initial margin factor now.
However if a decrease order does only decrease the size of a position and not it's collateral and therefore decreases the overall leverage of the position.
Then the collateral requirements are still always checked with the initial margin factor. This is an asymmetry to be aware of.
Recommendation
Consider to change or acknowledge this behavior.
However if the decision is made to change this be very careful as in the decrease case other condition are given as PnL is realized and fees apply. This may lead to not always improving the positions health and therefore such a change needs to be implemented with care.
No findings match.
More from GMX
All 44 reportsPut your code through the same review.
This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.
