Key Finance engaged Guardian to review the security of its GMX rewards solution, GMX Key. From the 28th of March to the 10th of April, a team of 2 auditors reviewed the source code in scope. The auditing approach championed manual analysis to uncover novel exploits and verify intended behavior with ancillary verification from formal methods such as contract fuzzing. All findings and remediations have been recorded in the following report.
- Published
- Review window
- March 28 to April 10, 2023
- Language
- Solidity
- Chains
- Arbitrum, Avalanche
- Sector
- Staking
- 0 Critical
- 3 High
- 9 Medium
- 5 Low
- 0 Informational
Scope
Overview
Key Finance engaged Guardian to review the security of its GMX rewards solution, GMX Key. From the 28th of March to the 10th of April, a team of 2 auditors reviewed the source code in scope. The auditing approach championed manual analysis to uncover novel exploits and verify intended behavior with ancillary verification from formal methods such as contract fuzzing. All findings and remediations have been recorded in the following report.
Issues Detected Throughout the course of the audit numerous high impact issues were uncovered and promptly remediated by the Key Finance team. Several issues impacted the fundamental behavior of the protocol, Guardian believes these issues to be resolved. However numerous changes were made to the codebase after Guardian’s review, for this reason Guardian supports an independent security audit of the protocol at a finalized frozen commit.
Findings 17
-
LPS-1 High Rewards May Be Stolen Logical Error Resolved
Description
The
uniswapV3Stakercontract which theLPStakerinteracts with allows any arbitrary address to directly call theunstakeTokenfunction and unstake for any depositor after the incentive keyendTime.When a deposit is unstaked from an incentive key directly from the
uniswapV3Staker, those rewards will be incremented for theLPStakercontract, but not credited towards the user who staked. Therefore malicious stakers may unstake for other stakers and immediately claim their rewards as their own by unstaking through theLPStakercontract.Recommendation
Consider using a modified version of the
uniswapV3Stakerwhere the depositor must always be the one to unstake. Otherwise be sure to manage the incentive keys extremely carefully and never allow an incentive key to reach itsendTimewhile users have staked for it.Resolution
Key Team: A modified version of the
uniswapV3Stakerwas implemented. -
STK-1 High Reward Compounds Are Sandwichable Sandwich Attack Resolved
Description
There exists no fee or lockup period associated with staking to receive a portion of the rewards compounded during the
updateAllRewardsForTransferReceiverAndTransferFeefunction.A malicious actor may simply buy GMXKey and stake right before the
updateAllRewardsForTransferReceiverAndTransferFeefunction to immediately accrue a portion of the collected rewards that were meant to be attributed to other stakers. The malicious actor can then immediately claim these rewards, unstake and sell GMXKey after the reward compound, therefore stealing rewards from other stakers.Recommendation
Consider implementing a staking/unstaking fee or a “warmup period” where stakers cannot accrue rewards.
Resolution
Key Team: A new approach to rewards including reward periods was adopted.
-
TREC-1 High Lost WETH Rewards Upon Upgrade Lost Rewards Resolved
Description
During the account transfer process, the
RewardRouterV2does notclaimForAccountfrom thefeeGMXTracker. Therefore any accrued WETH rewards will not be transferred to the new address upon upgrade of theTransferReceiver.The
TransferReceiverwill then have no means of claiming these WETH rewards and injecting them into theRewardssystem as theamountToMintcalculation will underflow and revert since the receiver’s staked balances have been transferred out.Recommendation
Require WETH rewards to be claimed and injected into the
Rewardssystem before initiating theTransferReceiverupgrade process.Resolution
Key Team: The Rewards logic was updated to allow any remaining WETH to be collected.
-
GLOBAL-1 Medium Centralization Risk Centralization / Privilege Acknowledged
Description
The
adminaddress holds the ability to negatively impact the system in numerous ways, including but not limited to:- Take all esGMX, sGMX and bnGMX via
reserveSignalTransferandsignalTransfer. - Use the
withdrawTokensfunction to take any non-WETH ERC20 rewarded to theTransferReceiver. - Lock all staked Uniswap V3 LP positions by pausing the
LPStakercontract. - Lock all
GMXKeyandMPKeystakes by pausing theStakercontract. - Raise fees to 100% in the
Rewardscontract.
Recommendation
Ensure that the
adminaddress is a multi-sig, optionally with a timelock for improved community trust and oversight. Attempt to limit the scope of the admin address permissions such as locking stakes and raising fees to 100%.Resolution
Key Team: We have removed the pausable modifier for functions that would lock V3 positions and privileged addresses will be multi-sigs.
- Take all esGMX, sGMX and bnGMX via
-
TREC-2 Medium Invalid Assumption Logical Error Resolved
Description
In the
acceptTransferfunction it is assumed thatA maximum of ~7% amount of GMX (as esGMX)would be added, however that assumption does not hold in several cases.A user could have removed their sGMX and only been left with esGMX and bnGMX or a user may have accepted a transfer from another account which perturbed this ratio.
Recommendation
Do not rely on this assumption holding and remove the comment. If it is paramount that only a small percentage of esGMX is added, add an explicit check.
Resolution
Key Team: The comment has been removed.
-
TREC-3 Medium Unexpected Rewards Protocol Manipulation Resolved
Description
The allowance is used to determine how much WETH to inject into the
Rewardssystem and it is incremented based on the current balance of theTransferReceiver.However the balance of the
TransferReceivercan be inflated by transferring WETH directly to theTransferReceivercontract. Therefore rewards that are not explicitly from GMX are able to enter theRewardssystem.Additionally, it is possible that
privateTransferModeis turned off for either esGMX or bnGMX in the future, which could also potentially perturb theRewardssystem.Recommendation
Consider if outside WETH should be included in the accounted rewards. If not, implement a before and after balance check when calling
rewardRouter.handleRewardsto get the actual WETH amount received from GMX.Additionally, have a plan for the scenario where
privateTransferModeis turned off for eitheresGMXor bnGMX.Resolution
Key Team: The recommended before and after check was implemented.
-
LPS-2 Medium onERC721Received Reentrancy Reentrancy Resolved
Description
During the
unstakeAndWithdrawLpTokenfunction, themsg.sendermay re-enter into theonERC721Receivedfunction upon thewithdrawTokencall by transferring the withdrawn Uniswap V3 LP NFT back to theLPStaker.This reentrancy can yield an unexpected state where the token still exists in the
tokensStakedlist for the owner, but not in theidToOwnerorstakedIndex. Such an unexpected state may have unintended consequences and effect frontend systems reading from the contract or third party systems built on top of theLPStaker.Recommendation
Move the
withdrawTokencall to the end of theforloop to follow Check-Effects-Interactions. Alternatively, add a reentrancy check to theonERC721Receivedfunction.Resolution
Key Team: Check-Effects-Interactions was adopted.
-
STK-2 Medium Users May Stake For Others Unexpected Behavior Resolved
Description
The
stakefunction in theStakercontract allows users to stake for any address rather than just their own. This can cause unexpected consequences for contract systems interfacing with theStakercontract, especially if the necessary staking “warmup period” is implemented.Recommendation
Reconsider if this feature is necessary, and if so carefully document it and consider its impacts when combined with the solution for STK-1.
Resolution
Key Team: Users can no longer stake for others in the Staker contract.
-
ADM-1 Medium Admin Role Changes Should Be Two Step Unnecessary Risk Resolved
Description
As addressed in GLOBAL-1, the admin address carries numerous important abilities for the system.
However the
changeAdminfunction allows the admin address to be errantly transferred to the wrong address as it does not use a two-step transfer process.Recommendation
Implement a two step “push” and “pull” admin transfer process. If it is desired to have a method to relinquish ownership, implement a separate function to do so.
Resolution
Key Team: The recommended push and pull transfer process was adopted.
-
BTOK-1 Medium Dangerous Approve Frontrunning Resolved
Description
The
BaseTokenonly exposes the dangerousapprovefunction rather than an additional alternativeincreaseAllowancefunction.Recommendation
Implement an
increaseAllowancefunction so that users may increase their allowances without risk of frontrunning.Resolution
Key Team: The recommended
increaseAllowancefunction was implemented. -
LPS-3 Medium Fee-On-Transfer Tokens Compatibility Acknowledged
Description
The
LPStakercontract is not compatible with fee-on-transfer tokens for therewardTokenas it relies on theuintreturned from theuniswapV3Staker claimRewardfunction to increment the reward mapping.Fee on transfer tokens will cause this returned value to be inaccurate and potentially leave users unable to claim their rewards and potentially locked in the contract.
It should also be noted that rebase tokens or other balance altering tokens will not be accurately accounted for in a similar way.
Recommendation
Consider if fee-on-transfer, rebase, or any similar tokens should be supported. If so, add before and after balance checks for the
claimRewardfunction to measure the reward claimed accurately.Resolution
Key Team: The
rewardTokenwill never be a fee-on-transfer token. -
REW-1 Medium Chain Incompatibility Compatibility Resolved
Description
The
withdrawTofunction is used on WETH in the_transferAsETHfunction. This function is supported on Arbitrum, however it is not supported on the Avalanche C-chain or other networks that GMX may deploy on.Recommendation
Do not use the
withdrawTofunction when deploying on Avalanche or other chains. Instead implement a method to receive Ether and relay it to thetoaddress.Resolution
Key Team: The
withdrawTofunction has been replaced withwithdraw. -
GLOBAL-2 Low Custom Reverts Optimization Acknowledged
Description
Throughout the codebase
requirestatements are used when instead custom errors may be implemented withifcondition checks.Recommendation
Replace
requirestatements withifstatements and custom error reverts to save gas.Resolution
Key Team: Opted to keep the
requirestatements. -
GLOBAL-3 Low Use Standard ReentrancyGuard Best Practices Resolved
Description
Throughout the codebase a non OpenZeppelin
ReentrancyGuardcontract is used. The customReentrancyGuardcontract is inferior as it uses aboolean _guardstorage variable.Recommendation
Use the OpenZeppelin
ReentrancyGuard.Resolution
Key Team: Implemented the recommended OZ
ReentrancyGuard. -
REW-2 Low Redundant Transfers Optimization Resolved
Description
When claiming and updating a reward for a
TransferReceiver, the fee is first transferred to theTransferReceiverbefore being transferred to themsg.sender.Recommendation
Consider implementing a
feeToaddress parameter on theupdateAllRewardsForTransferReceiverAndTransferFeefunction so that two redundant transfers are not needed.Resolution
Key Team: The suggested
feeToaddress was implemented. -
CNV-1 Low Inaccurate Comment Documentation Resolved
Description
In the
completeConversionandcompleteConversionToMpKeyfunctions it is stated thatthe sender'svesting tokens must be non-zerohowever the sender’s vesting tokens must be zero or else theacceptTransferon theRewardRouterwill revert.Recommendation
Update the inaccurate comments.
Resolution
Key Team: The comment was updated.
-
GLOBAL-4 Low Lack of Events Events Resolved
Description
Throughout the codebase there are functions that alter the contract state in a significant way without emitting an event.
For example the
signalTransferandreserveSignalTransferought to emit an event for third party systems to be able to read.Recommendation
Emit an appropriate event whenever a significant change is made in the contract system.
Resolution
Key Team: The suggested events were added.
No findings match.
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.
