Skip to content

Conversation

@RembrandtK
Copy link
Contributor

@RembrandtK RembrandtK commented Dec 16, 2025

Address open issues and recommendations in Graph_IssuanceAllocator_v01.

Refactoring to switch from PPM to absolute allocations has changed the context for several issues and resulted in a large proportion of issue responses being combined into one large commit (d2e83ed).

TRST-L-1 Reward reclaiming efficiency is significantly limited (b8e8159)

  • Added public reclaimRewards() for external contracts to reclaim
  • Updated AllocationManager to call reclaimRewards() for denied scenarios.

TRST-L-3 Inaccurate view functions for the zero-address target (55c2537)

  • Documented deliberate behavior of getTargetAllocation() and getTargetIssuancePerBlock() for address(0)

TRST-R-1 Follow naming conventions for non-public functions (8edca9a)

  • Added underscore prefix to private functions: notifyAllTargets()_notifyAllTargets(), accumulatePendingIssuance()_accumulatePendingIssuance()

TRST-R-2 Emit events for all types of mints for visibility (d2e83ed)

  • Added IssuanceSelfMintAllowance event emitted when self-minting allowances are calculated

TRST-R-3 Document security assumptions (d2e83ed)

  • Documented overflow safety assumptions
  • Documented initialization block range safety (lastDistributionBlock starts at block.number)
  • Clarified pause behavior and block tracking divergence

TRST-R-4 Improve reentrancy protection for IssuanceAllocator (d2e83ed)

  • Added ReentrancyGuardTransientUpgradeable using EIP-1153 transient storage
  • Applied to all governance functions modifying configuration

TRST-R-5 Clarify reclaim precedence (b8e8159)

  • Documented explicit precedence: subgraph denylist reclaim prioritized over indexer eligibility reclaim
  • Short-circuit pattern in _deniedRewards() checks SUBGRAPH_DENIED before INDEXER_INELIGIBLE

TRST-R-7 Fix wrong documentation (d2e83ed)

  • Corrected documentation: rate changes apply immediately and are used retroactively when distribution resumes
  • Clarified they don't apply from lastDistributionBlock

Response to TRST-L-3 "Inaccurate view functions for the zero-address target"

The current behaviour of getTargetAllocation() and getTargetIssuancePerBlock()
is deliberate and regarded as correct. These functions return assigned
allocations rather than effective minting amounts. This design choice is
supported by the following reasoning:

1. **Semantically correct**: The functions answer "what allocation is assigned
   to this target?" rather than "what does this target receive?".

2. **Consistent interface**: Callers can query the default target allocation
   uniformly, regardless of whether it's address(0) or not.

3. **Accounting utility**: When address(0) is used, the returned values
   represent the unallocated/unminted portion of issuance.

4. **Separation of concerns**: getTotalAllocation() provides the effective
   system-wide allocation that excludes unmintable portions.

The documentation has been enhanced to make this behaviour explicit for the
address(0) edge case, to avoid potential confusion.
@RembrandtK RembrandtK self-assigned this Dec 16, 2025
@openzeppelin-code
Copy link

openzeppelin-code bot commented Dec 16, 2025

Issuance allocator audit responses (for Graph_IssuanceAllocator_v01)

Generated at commit: 9488b9d83e6412ae2dc5c0785e0c3737e7a25c67

🚨 Report Summary

Severity Level Results
Contracts Critical
High
Medium
Low
Note
Total
3
5
0
14
38
60
Dependencies Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0

For more details view the full report in OpenZeppelin Code Inspector

@codecov
Copy link

codecov bot commented Dec 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.30%. Comparing base (48be37a) to head (9488b9d).

Additional details and impacted files
@@                   Coverage Diff                    @@
##           issuance-allocator-3    #1270      +/-   ##
========================================================
+ Coverage                 86.14%   86.30%   +0.16%     
========================================================
  Files                        45       45              
  Lines                      2345     2373      +28     
  Branches                    698      708      +10     
========================================================
+ Hits                       2020     2048      +28     
  Misses                      325      325              
Flag Coverage Δ
unittests 86.30% <100.00%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Addresses TRST-R-1: Follow naming conventions for non-public functions

Updated two private functions for consistency with the rest of the
codebase:
- notifyAllTargets() → _notifyAllTargets()
- accumulatePendingIssuance() → _accumulatePendingIssuance()

All private and internal functions now consistently use underscore
prefixes, improving code clarity and reducing potential for errors.
…nce 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.
…d security improvements

Major refactoring to improve clarity and address audit findings TRST-R-2, TRST-R-3, and TRST-R-4.

Core Changes

PPM to Absolute Rates Migration
- Changed from percentage-based allocations (PPM) to absolute token rates (tokens per block)
- Updated all allocation logic to use rates instead of percentages
- Maintains 100% allocation invariant: totalAllocatorRate + totalSelfMintingRate == issuancePerBlock
- Default target automatically adjusted to maintain invariant

Improved Naming
- Renamed `accumulatedSelfMinting` to `selfMintingOffset` for clarity
- Renamed `setDefaultAllocationAddress` to `setDefaultTarget`
- Event renamed: `DefaultAllocationAddressUpdated` to `DefaultTargetUpdated`
- Field names: `*PPM` to `*Rate` (totalAllocationRate, allocatorMintingRate, selfMintingRate)

API Changes
- Replaced `bool evenIfDistributionPending` parameter with `uint256 minDistributedBlock`
- More flexible control: allows requiring distribution to specific block before config changes
- Translation: `evenIfDistributionPending=true` → `minDistributedBlock=0`

Security Improvements

TRST-R-2: Event Visibility for Self-Minting
- Added `IssuanceSelfMintAllowance` event emitted when self-minting allowances are calculated
- Provides visibility into all minting activity, not just allocator-minting

TRST-R-3: Security Assumption Documentation
- Documented overflow safety assumptions with concrete examples
- Documented initialization block range safety (lastDistributionBlock starts at block.number)
- Added inline comments explaining division-by-zero impossibility
- Clarified pause behavior and block tracking divergence

TRST-R-4: Reentrancy Protection
- Added `ReentrancyGuardTransientUpgradeable` using EIP-1153 transient storage
- Applied to all governance functions that modify configuration
- `distributeIssuance()` intentionally NOT guarded (documented why it's safe)
- Protection against multi-sig signature exploitation vectors

Fix TRST-R-7: Correct pause behavior documentation for setter functions.
Rate changes now correctly documented as applying immediately and being
used retroactively when distribution resumes, rather than applying from
lastDistributionBlock.

Update documentation to reflect migration from PPM-based proportional
allocation to absolute rate-based system (tokens per block):
- Update all storage variable names and descriptions
- Replace PPM terminology with rate-based terminology throughout
- Document new default target mechanism and 100% allocation invariant
- Update function signatures to use minDistributedBlock instead of
  evenIfDistributionPending parameter
- Add documentation for new setDefaultTarget functions
- Update all event signatures with new parameters
- Add new error conditions and update existing ones
- Update view function return types and descriptions
- Clarify that notifications occur even when paused
@RembrandtK RembrandtK changed the title Issuance allocator audit responses (WIP) Issuance allocator audit responses (for Graph_IssuanceAllocator_v01) Dec 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants