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 == 0the function unstakes the user's full stake (implement the "unstake all" behavior), orUpdate the NatSpec documentation to reflect that passing
0is invalid and will revert.
Proof of Concept
User calls:
Expected behavior: function unstakes all user's funds from the validator and the transaction succeeds.
Actual behavior: transaction reverts with
InvalidAmount(0).
Was this helpful?