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

52931 sc high validators can not claim their commissions after the reward token removal

Submitted on Aug 14th 2025 at 11:49:48 UTC by @Slayer for Attackathon | Plume Network

  • Report ID: #52931

  • Report Type: Smart Contract

  • Report severity: High

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

  • Impacts:

    • Permanent freezing of funds

Description

Brief/Intro

The requestCommissionClaim function prevents validators from claiming earned commission after a reward token has been removed from the system. While the removeRewardToken function correctly updates accrued validator commissions, the commission claim process requires the token to still be active, creating a permanent lock on validator funds.

Vulnerability Details

When a reward token is removed:

// RewardsFacet.sol:removeRewardToken()
for (uint256 i = 0; i < $.validatorIds.length; i++) {
    uint16 validatorId = $.validatorIds[i];

    // Final update to current time to settle all rewards up to this point
    PlumeRewardLogic.updateRewardPerTokenForValidator($, token, validatorId);

    // Create a final checkpoint with a rate of 0 to stop further accrual definitively
    PlumeRewardLogic.createRewardRateCheckpoint($, token, validatorId, 0);
}

// Update the mapping
$.isRewardToken[token] = false;

The function correctly:

  • Settles all pending validator commission up to the removal timestamp

  • Stores commission in $.validatorAccruedCommission[validatorId][token]

  • Sets $.isRewardToken[token] = false

However, when validators try to claim this commission:

The _validateIsToken modifier implementation:

Problem flow:

1

Token removal and settling

  1. Token is removed → $.isRewardToken[token] = false.

  2. Validator commission is settled and stored in $.validatorAccruedCommission[validatorId][token].

2

Claim attempt

  1. Validator calls requestCommissionClaim(validatorId, removedToken).

  2. _validateIsToken(removedToken) checks $.isRewardToken[removedToken] → returns false.

  3. Function reverts with TokenDoesNotExist(token).

While users can claim rewards from removed tokens because RewardsFacet._validateTokenForClaim() includes fallback logic:

validators have no such mechanism.

Impact Details

Validators lose all accrued commission from removed reward tokens — effectively permanent freezing of those funds.

Proof of Concept

1
  1. Call removeRewardToken(...)$.isRewardToken[token] = false.

  2. Validator commission is updated and stored in $.validatorAccruedCommission[validatorId][token].

2
  1. Validator calls requestCommissionClaim(validatorId, removedToken).

  2. _validateIsToken(removedToken) checks $.isRewardToken[removedToken] → returns false.

  3. Function reverts with TokenDoesNotExist(token), blocking the claim.

References

(Add any relevant links to documentation or code)

Was this helpful?