Abracadabra Money engaged Guardian to review the security of its GMX V2 Market Integration. From the 26th of October to the 7th of November, a team of 3 auditors reviewed the source code in scope.
- Published
- Review window
- October 26 to November 7, 2023
- Language
- Solidity
- Chains
- Arbitrum
- Sector
- Lending
- 2 Critical
- 2 High
- 10 Medium
- 4 Low
- 0 Informational
Scope
Overview
Abracadabra Money engaged Guardian to review the security of its GMX V2 Market Integration. From the 26th of October to the 7th of November, a team of 3 auditors reviewed the source code in scope.
Findings 18
-
ORDA-1 Critical Wrong amount deposited into the DegenBox Logical Error Resolved
Description
In the
sendValueInCollateralfunction the amount provided as a parameter is acollateralShareamount (GM shares in the degen box), that amount is then converted to ashortTokenamount via an exchange rate.The
amountShortTokenis then sent to thedegenBox, however the amount (GM shares) is what is deposited.Therefore a GM token Shares amount will be treated as a short token amount, which may have severely different valuations depending on the exchange rate. Additionally this can often cause the liquidation to revert if the GM token is a lower value than the short token.
Recommendation
In the
sendValueInCollateralfunction, line 197:degenBox.deposit(IERC20(shortToken), address(degenBox), recipient, amount, 0);Should be replaced with:
degenBox.deposit(IERC20(shortToken), address(degenBox), recipient, amountShortToken, 0);
Resolution
Abracadabra Team: Remediated with commit: bda0214.
-
GMXC-1 Critical Liquidations Prevented By Request Expiration Protocol Manipulation Resolved
Description
During liquidation, if a user has an open order, the order is cancelled in order to retrieve the underlying tokens. However orders cannot be cancelled while within the
REQUEST_EXPIRATION_BLOCK_AGE.Therefore a malicious user can front-run liquidations and create an order to prevent liquidations. The
REQUEST_EXPIRATION_BLOCK_AGEis currently configured to 1200 blocks on Arbitrum. In practice, the time to execute an order in GMX should be ~2 seconds, however when the deposit or withdrawal feature is disabled on GMX the keeper will not execute or cancel orders.Therefore a malicious user can gain a ~5 minute grace period where they cannot be liquidated due to the
REQUEST_EXPIRATION_BLOCK_AGEwhen the deposit or withdrawal feature is disabled as the order will not be executed or cancelled by the keeper.Recommendation
Do not allow the creation of orders when an account is liquidatable.
Additionally, consider validating that the deposit and withdrawal feature are enabled before users are able to use the
ACTION_CREATE_ORDER.Resolution
-
GMXC-2 High amountToAdd Not Valued At The Collaterization Rate Logical Error Resolved
Description
When validating whether a borrow position is solvent, the
COLLATERIZATION_RATEis used to verify that the amount borrowed does not exceed the maximum percentage borrowable with the current collateral.However, the
COLLATERIZATION_RATEis not applied toamountToAdd, which is the amount of GM tokens expected to be obtained from a pending deposit.For example, assume MIM and GM have a 1-1 price and the
COLLATERIZATION_RATEis 75%. 10 GM tokens would allow borrowing 10 MIM rather than 7.5.As a result, the amount of MIM able to be borrowed is calculated to be larger than allowed, and the position is deemed solvent.
Recommendation
Value the
amountToAddat theCOLLATERIZATION_RATE.Resolution
Abracadabra Team: Resolved in commit 2c2d6c0.
-
GMOCL-1 High longToken Assumed To Be The indexToken Logical Error Acknowledged
Description
In the
_getfunction the price of the long token provided is the price of the index token, however not all GM markets have the long token as the index token.For example, the DOGE/USD GM market has Ether as its long token. In this case the price of ETH is provided as the price of DOGE which will be dramatically inaccurate.
Recommendation
Treat the long token separately from the index token, as these two are not guaranteed to be the same.
Resolution
Abracadabra Team: With the planned supported GM markets this oracle configuration is expected, however if we choose to support the DOGE or other similar gm markets in the future we will make a change.
-
GMXC-4 Medium Insolvent Liquidations Revert Liquidations Acknowledged
Description
Insolvent liquidations cannot occur if the Order contract does not have enough to cover the outstanding amount.
It is unlikely that positions are able to become insolvent as this would require unexpected immediate price action or inaction from liquidators, however it would be prudent to be able to handle such a case.
Recommendation
Consider implementing logic such that insolvent positions may be liquidated successfully.
Resolution
Abracadabra Team: We can do partial liquidations to avoid this.
-
ORDA-2 Medium Markets With ETH As The shortToken Are Gameable Protocol Manipulation Resolved
Description
In the event where a homogenous market or any GMX market had WETH as a short token, it would be possible for the user to withdraw their backing tokens through the
refundWETHfunction, without going through the expectedACTION_WITHDRAW_FROM_ORDERcook action, therefore avoiding the solvency check and allowing for a user to cause their position to go insolvent.Recommendation
Such a market is unlikely to exist, however it should be explicitly stated that markets with Ether as the short token are incompatible with the system.
Resolution
Abracadabra Team: Fixed with commit e265a7.
-
GMXC-5 Medium Blacklisted Callee Incorrectly Reset Logical Error Resolved
Description
In the
closeOrderfunction theblacklistedCalleesmapping entry is set tofalsefor the user’s order, however the user’s order was just set to the zero address and so therefore the previous order address entry was not correctly set tofalse.Recommendation
Update the
blacklistedCalleesmapping before zeroing out the user’s order.Resolution
Abracadabra Team: Fixed with commit 623f7d.
-
ORDA-3 Medium Anyone May Withdraw From Order After Close Access Control Resolved
Description
If a user were to ever close their Order but still have some funds remaining in the Order, anyone would be able to
ACTION_CALLthewithdrawFromOrderfunction from the Cauldron and take those funds. This can occur if a user were to callwithdrawFromOrderwithout their entire amount and setcloseOrder = True.Recommendation
Consider forcing a user to retrieve their entire
shortTokenandWETHbalance prior to closing an order with thewithdrawFromOrderfunction.Otherwise, clearly document that users should not leave their funds in an Order after closing it, as it becomes unblacklisted and accessible for all.
Resolution
Abracadabra Team: Fixed with commit c1fdaf.
-
GMOCL-2 Medium Use Of Deprecated latestAnswer Function Deprecation Acknowledged
Description
In the
_getfunction, thelatestAnswerfunction is used to read the latest price from the ChainlinkindexAggregatorandshortAggregator.However the
latestAnswerfunction is deprecated and should be replaced by alatestRoundDatacall with heartbeat validation as well as a sequencer uptime check for Arbitrum.Recommendation
Use the latestRoundData function to fetch the latest price from Chainlink and implement the necessary heartbeat and sequencer uptime validations. Blockchain Oracles for Connected Smart Contracts | Chainlink Documentation Chainlink Data Feeds Documentation | Chainlink Documentation
Resolution
Abracadabra Team: Acknowledged.
-
GMOCL-3 Medium More Restrictive PnL Type Used Protocol Risk Acknowledged
Description
In the
GmOracleWithAggregatorcontract the reported price uses theMAX_PNL_FACTOR_FOR_TRADERS PNL_TYPEto read the market token price from GMX. However this PnL type is less constrictive on the trader PnL than theMAX_PNL_FACTOR_FOR_DEPOSITS.Therefore when the market PnL is in between these two factors like so:
MAX_PNL_FACTOR_FOR_TRADERS < PnL in market < MAX_PNL_FACTOR_FOR_DEPOSITSThen the resulting price of the market token will be higher when measured using the more constrictive PnL factor for traders. Therefore the user’s collateral will be valued higher using the PnL factor for traders than compared to the PnL factor for deposits.
Out of an abundance of caution, it may be preferable to use the less constrictive max PnL for deposits, so that the collateral is not optimistically valued by capping the PnL to a lower amount. This is somewhat arbitrary as GM tokens cannot be redeemed as long as the pnl to pool ratio exceeds the
MAX_PNL_FACTOR_FOR_WITHDRAWALS, which is the lowest of these PnL factors.Recommendation
Consider using the less constrictive
MAX_PNL_FACTOR_FOR_DEPOSITSto read the price of the GM token.Resolution
Abracadabra Team: Acknowledged.
-
ORDA-4 Medium minOut Applies To Terminal Orders Logical Error Acknowledged
Description
In the
orderValueInCollateralfunction theminOutandminOutLongvalues are considered regardless of if the order is pending or if it has reached a terminal status.A deposit may have been cancelled or a withdrawal may have been executed, and therefore the Order contract has a distinct amount of short tokens, however the collateral value is still based on the minimum output that was configured for the order.
This directly discounts a user’s collateral as they will often receive more than the configured minimum amount.
Recommendation
If the order has reached a terminal status, return the balance of short tokens converted to market tokens as the
orderValueInCollateral.Resolution
Abracadabra Team: We want to incentivize users to close orders if they are completed and wanted to limit complexity.
-
GMXC-6 Medium Unwieldy Collateral Warning Acknowledged
Description
There are several characteristics of GM tokens that make them less than ideal as collateral.
Firstly, liquidations may be somewhat unwieldy for the liquidator as there is currently no market to swap GM tokens and unwrapping the GM tokens cannot occur in a single liquidation transaction.
Additionally, if the
pnlToPoolFactorin the GMX system is above theMAX_PNL_FACTOR_FOR_WITHDRAWALSGM tokens cannot be redeemed for their backinglongTokensorshortTokens.Recommendation
No changes may be necessary, simply be aware of this unwieldiness for liquidators, ensure that liquidators are still properly incentivized and consider this when determining the
COLLATERIZATION_RATEfor GM tokens.Resolution
Abracadabra Team: Acknowledged.
-
GMXC-7 Medium Share Amount As amountMarketToken Logical Error Resolved
Description
In the
liquidatefunction, when additional value is necessary to cover the borrowed amount and theOrder.sendValueInCollateralfunction is called, the providedamountMarketTokenis computed fromcollateralShare - userCollateralShare[user]. However this is a share amount rather than an elastic market token amount.Currently there is no strategy for GM tokens in the
DegenBox, however if there were to be a strategy that increased the elastic supply of GM tokens relative to the base shares, then the share value provided to theOrder.sendValueInCollateralwould be inaccurate.Recommendation
Consider converting the outstanding
collateralShareamount to a market token amount with theDegenBox.toAmountfunction before providing this amount as theamountMarketTokenfor thesendValueInCollateralfunction.Resolution
Abracadabra Team: Fixed with commit 431592.
-
CAUL-1 Medium Errant maxRate Validation Validation Resolved
Description
In the
cookfunction theACTION_UPDATE_EXCHANGE_RATEaction includes aminRateandmaxRateto bound the allowed updatedrate.The
rateis validated to be> minRateas well as> maxRateif amaxRateis set. However this misconstrues the meaning of amaxRateas therateshould be validated to be< maxRate.Recommendation
Validate that the
rateis< maxRatewhen themaxRate ≠ 0.Resolution
Abracadabra Team: Fixed with commit 55c602.
-
ORDA-5 Low Init Function Called Multiple Times Validation Resolved
Description
The
initfunction may not be called again if the cauldron address has been assigned a non-zero value, however there is no restriction that the_cauldronparameter is not the zero address.Within the context of the
GmxV2CauldronOrderAgentthis is not an issue as the_cauldronaddress provided to theinitfunction is always themsg.senderwhich cannot be the zero address.However it may be prudent to add validation that the
_cauldronparameter value is not the zero address to prevent vulnerabilities if theGmxV2CauldronRouterOrdercontract were to be used in a different context in the future.Recommendation
Consider adding validation such that the
_cauldronaddress cannot be the zero address in theinitfunction.Resolution
Abracadabra Team: Fixed with commit b03d57.
-
ORDA-6 Low Hardcoded Gas Limit Warning Resolved
Description
In the
GmvV2CauldronOrderAgentcontract, theCALLBACK_GAS_LIMITis hardcoded to1_000_000. However in some cases the GMX team may reduce the maximum allowed gas limit such that1_000_000exceeds the maximum cap.In this case it may be better to allow a reconfiguration of the
CALLBACK_GAS_LIMITthan to deploy a newGmxV2CauldronRouterOrderimplementation.Recommendation
Consider making the
CALLBACK_GAS_LIMITa configurable value by a trusted address. Otherwise be aware that the GMX team could reduce the maximum callback gas limit to below1_000_000which would prevent any deposits or withdrawals from being created.Resolution
Abracadabra Team: Fixed with commit 965af4.
-
CAUL-2 Low Lacking Caps On Init Validation Acknowledged
Description
In the
initfunction, there are no requirements that the assignedINTEREST_PER_SECOND,COLLATERIZATION_RATE,LIQUIDATION_MULTIPLIER, andBORROW_OPENING_FEEare within a reasonable range.Recommendation
Consider adding validation in the future to restrict the possible values for these critical values.
Resolution
Abracadabra Team: This is a design choice.
-
GMXC-8 Low Pending Orders Can Be Closed Validation Acknowledged
Description
With the
ACTION_WITHDRAW_FROM_ORDERaction it is possible to close an order in the Abracadabra system while the order in GMX is still pending.If the order is already closed in the Abracadabra system, then during the
afterDepositExecutionorafterWithdrawalCancellationcallbacks, the call to thecloseOrderfunction will revert and prevent any logic executing on the Abracadabra side, yet the order will still be executed.The
ACTION_WITHDRAW_FROM_ORDERaction must leave the position in a solvent state in Abracadabra so there is no imminent risk to the Abracadabra system. However this is an unusual edge case and can result in users losing funds, therefore it may make sense to explicitly disallow it.Recommendation
Consider disallowing the
ACTION_WITHDRAW_FROM_ORDERaction when an order is active.Resolution
Abracadabra Team: This is an edge case we expect only to be possible to custom frontends or direct contract interaction.
No findings match.
More from Abracadabra Money
Put 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.
