runNextAction in PerpetualVault is triggered by keepers to continue the current workflow and the next action is decided based on nextAction.selector. In case there is not nextAction.selector saved, the function will execute the COMPOUND workflow which aims to utilize collateralToken tokens and swap them to indexToken or use them as a collateral to long/short indexToken.
This design has a problem when keeper want to run the COMPOUND workflow. There is not any guarantee that the system wont go into DEPOSIT flow between the time of submitting the keeper's transaction and the time it is executed. On Arbitrum, the chances are really low that it can happen unintentionally, but in Avalanche where mempool is not completely private (stakers can see mempool and do MEV), it is possible that COMPOUND workflow is maliciously or unintentionally frontrun.
Taking a look into how DEPOSIT and COMPOUND flows are handled, we can see that they accept the same parameters and do the same actions. The problem is that if parameters passed are intended for COMPOUND workflow, they will be used for DEPOSIT.
DEPOSIT:
COMPOUND:
For cases different than 1x Leverage Long, the main difference would be acceptablePrice. Not sure how it is decided off-chain and how users agree with that price, but if price for COMPOUND operation is usually set to lower value than in DEPOSIT, user will suffer from this slippage.
For the 1x Leverage Long case, it can have bigger consequences since passed metadata will be used to execute the swap operation and result from swap will be used to determine the amount of shares user will get.
Consider the following example:
There is 1000 idle tokens in PerpetualVault and keeper try to run COMPOUND operation. For this, metadata is constructed to swap those 1000 tokens.
User tries to deposit 100 tokens and turn the protocol flow into DEPOSIT.
Now, DEPOSIT flow will be executed with metadata to swap 1000 tokens and result of DEX swap is used to calculate user's shares allocation.
This will result in shares equal to depositing 1000 tokens instead of shares equal to actual deposit.
Taking a look into _runSwap() to verify scenario above:
Unexpected behavior.
Possible incorrect calculations for user deposits.
Manual review.
Consider adding an explicit way to start COMPOUND operation. For example as a parameter of runNextAction().
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.