For the complete documentation index, see llms.txt. This page is also available as Markdown.

49919 sc insight unstake function does not unstake all as mentioned in the natspec

Submitted on Jul 20th 2025 at 15:04:14 UTC by @holydevoti0n for Attackathon | Plume Network

  • Report ID: #49919

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/facets/StakingFacet.sol

  • Impacts: Users cannot unstake all funds using the documented zero-amount method.

Description

Summary

The unstake function in StakingFacet.sol contradicts its NatSpec documentation regarding zero-amount behavior. The NatSpec states that passing amount = 0 should unstake all funds, but the implementation reverts when amount == 0, preventing users from unstaking their complete stake through the documented method.

Vulnerability Details

The NatSpec explicitly documents that passing 0 as the amount parameter should trigger an "unstake all" behavior. However, both the public function and the internal implementation revert when amount == 0.

Snippet from the repository (link preserved): https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/plume/src/facets/StakingFacet.sol#L371-L373

   function unstake(uint16 validatorId, uint256 amount) external returns (uint256 amountUnstaked) {
@>        if (amount == 0) {
@>            revert InvalidAmount(0);
@>        }
        return _unstake(validatorId, amount);
    }
    
    
    /**
     * @notice Internal logic for unstaking, handles moving stake to cooling or parked.
     * @param validatorId ID of the validator to unstake from.
@>     * @param amount The amount of PLUME to unstake. If 0, unstakes all.
     * @return amountToUnstake The actual amount that was unstaked.
     */
    function _unstake(uint16 validatorId, uint256 amount) internal returns (uint256 amountToUnstake) {
        ...
        // Validate unstaking conditions
        _validateValidatorForUnstaking(validatorId);
@>        if (amount == 0) {
@>            revert InvalidAmount(amount);
@>        }
        ...
     }

Impact

Users cannot unstake their complete stake using the documented zero-amount method, because the function reverts with InvalidAmount(0) instead of unstaking all the user's funds.

Recommendation

Either:

  • Update the implementation so that when amount == 0 the function unstakes the user's full stake (implement the "unstake all" behavior), or

  • Update the NatSpec documentation to reflect that passing 0 is invalid and will revert.

Proof of Concept

1
  1. User calls:

2
  1. Expected behavior: function unstakes all user's funds from the validator and the transaction succeeds.

3
  1. Actual behavior: transaction reverts with InvalidAmount(0).

Was this helpful?