DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

runNextAction() Incorrectly Assumes positionIsClosed == false

Summary

  • runNextAction() function assumes that the position remains open when executing the next action.
    However, external factors (such as liquidations, manual keeper interventions, or market movement) may close the position before runNextAction() executes. If this happens the function could wrongly executes an increase action on a non-existence position, leading to incorrect trades and inconsistent contract state.

Vulnerability Details

  • The keeper calls run(false, isLong, prices, metadata), intending to close an open position.

  • The function successfully closes the position and sets nextAction.selector = INCREASE_ACTION, assuming the next step will reopen a new trade.

  • Before runNextAction() is executed, something unexpected happens:

    • The market moves significantly, making the planned increase trade invalid.

    • A liquidation event occured, setting positionIsClosed = true.

    • A keeper manually intervenes and cancel the trade.

  • The function blindly executes the increase action, assuming the position is still open.

  • Since the position is actually closed this can lead to:

    • An unintended new position opening.

    • A trade failure due to invalid conditions

    • Incorrect vault accounting.

Impact

  • Trading errors

  • State inconsistency

  • Potential exploit: An attacker or a front-runner could manipulate market conditions to trigger a liquidation before runNextAction() runs, potentially forcing unintended trades.

Tools Used

Manual Review

Recommendations

Before executing _createIncreasePosition(), add a check to ensure positionIsClosed == false:

if (_nextAction.selector == NextActionSelector.INCREASE_ACTION) {
(bool _isLong) = abi.decode(_nextAction.data, (bool));
// Ensure the position is actually open before executing an increase
if (positionIsClosed) {
revert Error.positionAlreadyClosed();
}
if (_isLongOneLeverage(_isLong)) {
_runSwap(metadata, true, prices);
} else {
// swap indexToken that could be generated from the last action into collateralToken
// use only DexSwap
if (
IERC20(indexToken).balanceOf(address(this)) * prices.indexTokenPrice.min >= ONE_USD
) {
(, bytes memory data) = abi.decode(metadata[1], (PROTOCOL, bytes));
_doDexSwap(data, false);
}
(uint256 acceptablePrice) = abi.decode(metadata[0], (uint256));
_createIncreasePosition(_isLong, acceptablePrice, prices);
}
// ....
Updates

Lead Judging Commences

n0kto Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

Support

FAQs

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