Steadefi

Steadefi
DeFiHardhatFoundryOracle
35,000 USDC
View results
Submission Details
Severity: medium
Invalid

`Compound()` will not work if there is only TokenA/TokenB in the trove.

Summary

The compound() function is designed to deposit Long tokens, Short tokens, or airdropped ARB tokens to the GMX for compounding. However, it will only work if there is ARB token in the trove. If there are only Long/Short tokens in the trove without any ARB, the function will not work.

Vulnerability Details

The compound() function is intended to be called by the keeper once a day to deposit all the Long/Short or ARB tokens to the GMX for further compounding. However, the logic for depositing to the GMX is restricted by the condition that the trove must always hold an airdropped ARB token.

Here is the relevant code snippet from the GitHub repository:

//@audit compound if only ARB is there, what about tokenA and tokenB?
if (_tokenInAmt > 0) {
self.refundee = payable(msg.sender);
self.compoundCache.compoundParams = cp;
ISwap.SwapParams memory _sp;
_sp.tokenIn = cp.tokenIn;
_sp.tokenOut = cp.tokenOut;
_sp.amountIn = _tokenInAmt;
_sp.amountOut = 0; // amount out minimum calculated in Swap
_sp.slippage = self.minSlippage;
_sp.deadline = cp.deadline;
GMXManager.swapExactTokensForTokens(self, _sp);
GMXTypes.AddLiquidityParams memory _alp;
_alp.tokenAAmt = self.tokenA.balanceOf(address(this));
_alp.tokenBAmt = self.tokenB.balanceOf(address(this));
self.compoundCache.depositValue = GMXReader.convertToUsdValue(
self,
address(self.tokenA),
self.tokenA.balanceOf(address(this))
)
+ GMXReader.convertToUsdValue(
self,
address(self.tokenB),
self.tokenB.balanceOf(address(this))
);
GMXChecks.beforeCompoundChecks(self);
self.status = GMXTypes.Status.Compound;
_alp.minMarketTokenAmt = GMXManager.calcMinMarketSlippageAmt(
self,
self.compoundCache.depositValue,
cp.slippage
);
_alp.executionFee = cp.executionFee;
self.compoundCache.depositKey = GMXManager.addLiquidity(
self,
_alp
);
}

The code checks if there is a positive _tokenInAmt (representing ARB tokens) and proceeds with the depositing and compounding logic. However, if there is no ARB token but only tokenA and tokenB in the trove, the compounding will not occur and the tokens will remain in the compoundGMX contract indefinitely.

It is important to note that the airdrop of ARB tokens is a rare event, making it less likely for this condition to be met. Therefore, if there are no ARB tokens but a significant amount of tokenA and tokenB in the trove, the compounding will not take place.

Impact

If the compounding doesn’t happen this could lead to the indirect loss of funds to the user and loss of gas for the keeper who always calls this function just to transfer tokens and check the balance of ARB.

Tools Used

manual review

Recommendations

To mitigate this issue, it is important to always check if either tokenA/tokenB or ARB is present in the trove. If either of these is present, then proceed with the compound action. Otherwise, return.

if (_tokenInAmt > 0 || self.tokenA.balanceOf(address(this) > 0 || self.tokenB.balanceOf(address(this)) ) {
self.refundee = payable(msg.sender);
self.compoundCache.compoundParams = cp;
ISwap.SwapParams memory _sp;
_sp.tokenIn = cp.tokenIn;
_sp.tokenOut = cp.tokenOut;
_sp.amountIn = _tokenInAmt;
_sp.amountOut = 0; // amount out minimum calculated in Swap
_sp.slippage = self.minSlippage;
_sp.deadline = cp.deadline;
GMXManager.swapExactTokensForTokens(self, _sp);
GMXTypes.AddLiquidityParams memory _alp;
_alp.tokenAAmt = self.tokenA.balanceOf(address(this));
_alp.tokenBAmt = self.tokenB.balanceOf(address(this));
self.compoundCache.depositValue = GMXReader.convertToUsdValue(
self,
address(self.tokenA),
self.tokenA.balanceOf(address(this))
)
+ GMXReader.convertToUsdValue(
self,
address(self.tokenB),
self.tokenB.balanceOf(address(this))
);
GMXChecks.beforeCompoundChecks(self);
self.status = GMXTypes.Status.Compound;
_alp.minMarketTokenAmt = GMXManager.calcMinMarketSlippageAmt(
self,
self.compoundCache.depositValue,
cp.slippage
);
_alp.executionFee = cp.executionFee;
self.compoundCache.depositKey = GMXManager.addLiquidity(
self,
_alp
);
}
Updates

Lead Judging Commences

hans Auditor
over 1 year ago
hans Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Compound only works if bonus reward exists

Impact: Medium Likelihood: Medium

Steadefi Lead Judge
over 1 year ago
hans Auditor
over 1 year ago
0xanmol Submitter
over 1 year ago
hans Auditor
over 1 year ago
Steadefi Lead Judge
over 1 year ago
0xanmol Submitter
over 1 year ago
hans Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

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