The use of the gmxLock modifier instead of checking isLongOneLeverage(beenLong) inside the cancelFlow() function could have prevented the keeper from cancelling a flow that is not a 1x long leverage. Luckily, there is an onlyOwner setVaultState(...) function that could reset temporarily the _gmxLock parameter to bypass the modifier. Nonetheless, the cancelFlow() is badly implemented, it is not behaving the way it should.
Let's consider the scenario where run(true, false,...) is called by the keeper when there are no current positions that are opened (positionIsClosed is true) and there is a sufficiant amount of collateral tokens in the contract (_isFundIdle() is true).
These lines of code will be executed:
The subcall to createIncreasePosition(false,...)__ will set _gmxLock to true to lock the contract from the moment a position is opened to the moment of the callback.
Now the gmxLock modifier will revert untill _gmxLock is set again to false (during the callback).
Now the keeper tries to cancel the flow but will not be able because the call will revert because of the gmxLock modifier:
Luckily, there's this onlyOwner function that saves the day for the keeper, owner will call it to change _gmxLock to false temporarily, just for the keeper to be able to call cancelFlow() successfully.
It could have prevented the keeper from cancelling a flow that is not a 1x long leverage if there wasn't the onlyOwner setVaultState(...) function to set _gmxLock to false. Regardless, even though no funds are at risk, the function is incorrect, the state is not be handled appropriately.
Manual review
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.