You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: enable forced reward reclaiming for TRST-L-1 and clarify precedence for TRST-R-5
Addresses TRST-L-1: "Reward reclaiming efficiency is significantly limited"
Addresses TRST-R-5: "Clarify reclaim precedence"
The TRST-L-1 audit finding identified that reward reclaiming through takeRewards()
is flawed because a rational indexer who would not receive rewards would not
trigger the rewarding logic in the first place. The recommended mitigation is to
add calls from SubgraphService so that any entity can force a reclaim of denied
rewards. (Not adding to StakingExtension as it is deprecated and will soon not
be used.)
The TRST-R-5 finding noted that the precedence when both denial reasons apply
should be documented. Added explicit documentation that subgraph denylist
reclaim is prioritized over indexer eligibility reclaim.
Key changes:
1. Created RewardsReclaim library with canonical reclaim reason constants
using bytes32 identifiers (like OpenZeppelin roles) for extensibility
2. Migrated RewardsManagerStorage from separate reclaim address storage to
extensible mapping:
- Old: indexerEligibilityReclaimAddress, subgraphDeniedReclaimAddress
- New: mapping(bytes32 => address) reclaimAddresses
3. Replaced type-specific setters with generic setReclaimAddress(bytes32, address)
4. Refactored RewardsManager.takeRewards() with early return for zero rewards
and extracted helper functions:
- _calcAllocationRewards(): extract allocation data calculation
- _reclaimRewards(): common reclaim logic with named return value
- _deniedRewards(): implements short-circuit pattern with precedence
(SUBGRAPH_DENIED checked before INDEXER_INELIGIBLE)
5. Added public reclaimRewards() for external contracts to reclaim rewards
with custom reasons and data
6. Updated AllocationManager._presentPOI() to explicitly call reclaimRewards()
with specific reasons (STALE_POI, ALTRUISTIC_ALLOCATION, ZERO_POI,
ALLOCATION_TOO_YOUNG) instead of relying on takeRewards(). This enables
forced reclaiming of denied rewards, addressing the core TRST-L-1 issue.
7. Updated tests and mocks to use new bytes32-based API with RewardsReclaim
constants
This allows any entity to force reclaim of denied rewards through SubgraphService,
and enables future extension with new reclaim reasons without contract changes.
* @notice Checks for and handles denial and reclaim of rewards due to indexer eligibility
593
-
* @dev If denied, emits RewardsDeniedDueToEligibility event and mints to reclaim address if configured
600
+
* @notice Check if rewards should be denied and attempt to reclaim them
601
+
* @param rewards Amount of rewards to check
594
602
* @param indexer Address of the indexer
595
603
* @param allocationID Address of the allocation
596
-
* @param rewards Amount of rewards that would be distributed
597
-
* @return True if rewards are denied, false otherwise
598
-
*/
599
-
function _rewardsDeniedDueToIndexerEligibility(
604
+
* @param subgraphDeploymentID Subgraph deployment ID for the allocation
605
+
* @return denied True if rewards should be denied (either reclaimed or dropped), false if they should be minted
606
+
* @dev First successful reclaim wins - checks performed in order with short-circuit on reclaim:
607
+
* 1. Subgraph deny list: emit RewardsDenied. If reclaim address set → reclaim and return (STOP, eligibility not checked)
608
+
* 2. Indexer eligibility: Checked if subgraph not denied OR denied without reclaim address. Emit RewardsDeniedDueToEligibility. If reclaim address set → reclaim and return
609
+
* Multiple denial events may be emitted only when multiple checks fail without reclaim addresses configured.
610
+
* Any failing check without a reclaim address still denies rewards (drops them without minting).
0 commit comments