GMX engaged Guardian to review the security of the Chainlink real time pricing automation system for GMX V2. From the 4th of September to the 18th of September, a team of 3 auditors reviewed the source code in scope.
- Published
- Review window
- September 4 to 18, 2023
- Language
- Solidity
- Chains
- Arbitrum, Avalanche
- Sector
- Infrastructure
- 2 Critical
- 1 High
- 2 Medium
- 8 Low
- 0 Informational
Scope
Overview
GMX engaged Guardian to review the security of the Chainlink real time pricing automation system for GMX V2. From the 4th of September to the 18th of September, a team of 3 auditors reviewed the source code in scope.
Findings 13
-
GLOBAL-1 Critical Orders Requiring More Than 5 Million Gas Cannot Execute Insufficient Gas Resolved
Description
The Chainlink automation keepers are configured to send 5,000,000 gas with each execution, however GMX deposits, withdrawals, and orders may often require more than 5,000,000 gas to execute.
In the general.ts configuration file the
increaseOrderGasLimitanddecreaseOrderGasLimitare configured to4_000_000, additionally theminAdditionalGasForExecutionis configured to1_000_000. Therefore any increase or decrease order including a callback with a nonzerocallbackGasLimitcannot be executed by the Chainlink automation keepers.Additionally the
singleSwapGasLimitis configured to1_000_000, therefore deposits and withdrawals with 4 or more total swaps in thelongTokenSwapPathandshortTokenSwapPathare unable to be executed by the Chainlink automation keepers.Recommendation
Increase the configured gas amount to as high as 15,000,000 to ensure that even the most expensive of actions can be executed on GMX V2.
Resolution
Chainlink Team: The configuration was adjusted to 13,000,000 gas after discussing with the GMX team.
-
WTDA-1 Critical Withdrawals With Swaps Are Incompatible Logical Error Resolved
Description
The
longTokenSwapPathand theshortTokenSwapPathof a withdrawal cannot be decoded. This is becauseWithdrawalEventUtils.emitWithdrawalCreateddoes not emit the swap paths on a Withdrawal.Consequently, the withdrawal automation becomes unusable whenever a user requires a swap post-withdrawal.
Recommendation
Add the
longTokenSwapPathandshortTokenSwapPathto theWithdrawalCreatedevent. Afterwards, modifyWithdrawalAutomationto decode these paths and_addPropsToMappingto set the necessary feeds.Resolution
-
GLOBAL-2 High Anyone May performUpkeep Access Control Resolved
Description
There is no access control for the
performUpkeepfunction, therefore any arbitrary address may execute an order. On a network with a public mempool, such as Avalanche, any arbitrary user may observe the Chainlink keeper’s transaction and copy theperformDatato execute their own deposit, withdrawal, or order.A malicious actor can therefore front-run the execution of other user’s orders to manipulate price impact such that the actor stands to gain a profit at the user’s detriment.
Recommendation
Add access controls to the
performUpkeepfunction in theMarketAutomation,DepositAutomation, andWithdrawalAutomationcontracts.Once access controls are added to the
performUpkeepfunction, it should be noted that the permissioned caller still holds the ability to decide execution ordering, controlling the price impact experienced by orders.Resolution
Chainlink Team: The suggested
onlyForwarderaccess control was added in commit 0a7edc2. -
MKTA-1 Medium performUpkeep Can Be Used To Execute Any orderType Validation Acknowledged
Description
Using the
performUpkeepfunction, the Chainlink keeper may execute any order, even if the order is not aMarketIncrease,MarketDecrease, orMarketSwap.However the
MarketAutomationcontract is explicitly designed to execute only market orders, therefore the scope of which orders can be executed with theperformUpkeepfunction should be limited by validating theorderTypefrom thedataStore.Recommendation
Validate that the order being executed is indeed a
MarketIncrease,MarketDecrease, orMarketSwap.Resolution
Chainlink Team: Acknowledged.
-
GLOBAL-3 Medium FeedIds Must Be Set For Every Token Configuration Resolved
Description
Deposits, withdrawals and orders may use swap paths including any token supported on the GMX V2 platform.
Therefore every supported token must be assigned a valid functioning
feedId, otherwise deposits, withdrawals and orders may be unable to be executed using the Chainlink keeper or may become cancelled unexpectedly.Recommendation
Ensure that every token on the GMX V2 platform is supported by a valid
feedId.Additionally, implement validation in the
checkLogfunction such that if afeedIdis not configured for a token that is necessary for the action, the action is not executed by the Chainlink keeper and is instead executed by the default keeper.Resolution
Chainlink Team: The recommended validation was added in commit a21b0b9.
-
MKTA-2 Low Typo Typo Resolved
Description
The comment on line 51 reads
a feed lookup lookupwhere the wordlookupis repeated twice.Recommendation
Remove the second instance of
lookup.Resolution
Chainlink Team: The recommendation was implemented in commit ffed912.
-
GLOBAL-4 Low Accept Ether Optimization Optimization Acknowledged
Description
The
DepositAutomation,MarketAutomation, andWithdrawalAutomationcontracts have noreceivefunction and therefore cannot receive gas remuneration from GMX V2 in native tokens.GMX V2 handles this by re-wrapping the native tokens and sending them to the keeper. However the keeper must pay for this additional re-wrapping gas expenditure on every transaction.
Recommendation
To avoid this additional gas expenditure on every transaction, implement a
receivefunction, with a way to retrieve the accumulated native tokens.Resolution
Chainlink Team: Acknowledged.
-
GLOBAL-5 Low Lack Of cannotExecute Modifier For checkLog Validation Acknowledged
Description
The
ILogAutomationcontract documentation mentions that acannotExecutemodifier should be added to thecheckLogfunction to ensure it can never be errantly called in a transaction, only simulated.However the
checkLogfunctions in theDepositAutomation,MarketAutomation, andWithdrawalAutomationcontracts lack anycannotExecuteor similar modifier.Recommendation
Consider whether a
cannotExecutemodifier should be added.If so, implement a
cannotExecutemodifier in theGMXAutomationBasecontract and add it to thecheckLogfunctions in theDepositAutomation,MarketAutomation, andWithdrawalAutomationcontracts.Resolution
Chainlink Team: Acknowledged.
-
GLOBAL-6 Low Inaccurate Comment Documentation Resolved
Description
In the
DepositAutomationandWithdrawalAutomationcontracts the comment on line 53 states//Decode Event Log 1, however both"DepositCreated"and"WithdrawalCreated"are emitted with Event Log 2.Recommendation
Update the comment to
// Decode Event Log 2.Resolution
Chainlink Team: The recommendation was implemented in commit ffed912.
-
GLOBAL-7 Low Key Contract Addresses May Not Be Updated Upgradeability Acknowledged
Description
In the
DepositAutomation,WithdrawalAutomation, andMarketAutomationcontracts thei_depositHandler,i_withdrawalHandler, andi_orderHandlervariables are declared asimmutable. Additionally, in theGMXAutomationBasecontract thei_dataStoreandi_readervariables are declaredimmutable.However it is possible that the respective contracts are upgraded or replaced, meaning that the existing Chainlink Automation contract is no longer functional. Therefore a new Automation contract would need to be deployed and whitelisted as a valid keeper in the event of a handler contract upgrade.
Recommendation
Consider if the
owneraddress should be able to update these contract addresses in the event of an upgrade.Resolution
Chainlink Team: Redeployment of an Automation contract is preferred on the Chainlink operational side.
-
GLOBAL-8 Low Block Number Provided As Time Documentation Acknowledged
Description
The
StreamsLookuperror labels the second to last parameter astime, it is unclear whether this is intended to be a timestamp.However a block number is provided for the
timein theStreamsLookuperror in thecheckLogfunction in each of theDepositAutomation,WithdrawalAutomation, andMarketAutomationcontracts.Recommendation
Verify whether the time parameter is intended to be a block number or timestamp, consider documenting what the time parameter represents in the
StreamsLookupCompatibleInterfaceinterface.Resolution
Chainlink Team: This is expected.
-
BASE-1 Low Missing NatSpec Documentation Resolved
Description
In the NatSpec for the
_flushMappingfunction, the addresses returned value is omitted.Recommendation
Add the addresses value to the NatSpec for the
_flushMappingfunction.Resolution
Chainlink Team: The recommendation was implemented in commit ffed912.
-
BASE-2 Low Typo Typo Resolved
Description
In the
_toHexStringfunction, the comment on line 101 states// Fixed buffer size for hexadecimalconvertion, howeverconversionis misspelled asconvertion.Recommendation
Replace
convertionwithconversion.Resolution
Chainlink Team: The recommendation was implemented in commit ffed912.
No findings match.
Invariants 1
The review's fuzzing suite asserted 1 invariant. 1 held.
Every invariant tested
| ID | Invariant | Result |
|---|---|---|
BASE-1 | _toHexString Matches OpenZeppelin’s toHexString output with a length of 32 bytes | Held |
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.
