Pending indexing payments and post-Horizon contract changes#1288
Pending indexing payments and post-Horizon contract changes#1288RembrandtK wants to merge 66 commits intomainfrom
Conversation
Fixes TRST-M-1 audit finding: Wrong TYPEHASH string is used for agreement updates, limiting functionality. * Fixed EIP712_RCAU_TYPEHASH to use correct uint64 types for deadline and endsAt fields (was incorrectly using uint256) * This prevents signature verification failures for RecurringCollectionAgreementUpdate
Fixes TRST-M-2 audit finding: Collection for an elapsed or canceled agreement could be wrong due to temporal calculation inconsistencies between IndexingAgreement and RecurringCollector layers. * Replace isCollectable() with getCollectionInfo() that returns both collectability and duration * Make RecurringCollector the single source of truth for temporal logic * Update IndexingAgreement to call getCollectionInfo() once and pass duration to _tokensToCollect()
Fixes signature replay attack vulnerability where old signed RecurringCollectionAgreementUpdate messages could be replayed to revert agreements to previous terms. ## Changes - Add `nonce` field to RecurringCollectionAgreementUpdate struct (uint32) - Add `updateNonce` field to AgreementData struct to track current nonce - Add nonce validation in RecurringCollector.update() to ensure sequential updates - Update EIP712_RCAU_TYPEHASH to include nonce field - Add comprehensive tests for nonce validation and replay attack prevention - Add RecurringCollectorInvalidUpdateNonce error for invalid nonce attempts ## Implementation Details - Nonces start at 0 when agreement is accepted - Each update must use current nonce + 1 - Nonce is incremented after successful update - Uses uint32 for gas optimization (supports 4B+ updates per agreement) - Single source of truth: nonce stored in AgreementData struct
Implements slippage protection mechanism to prevent silent token loss during rate-limited collections in RecurringCollector agreements. The implementation uses type(uint256).max convention to disable slippage checks, providing users full control over acceptable token loss during rate limiting. Resolves audit finding TRST-L-5: "RecurringCollector silently reduces collected tokens without user consent"
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Prevents stack-too-deep compiler error when running coverage without optimizer, caused by RecurringCollector contract complexity.
Add forge-lint disable comments for RCA/POI acronym casing in
function and variable names. Remove unused Allocation and
IDataServiceFees imports. Replace unsafe bytes32("poi") cast
with keccak256("poi").
…service coverage - Revert strict inequality conversions (> x-1, < x+1) back to (>=, <=) and suppress gas-strict-inequalities with solhint comments instead - Suppress gas-small-strings, function-max-lines solhint warnings - Add --ir-minimum to subgraph-service forge coverage to fix stack too deep - Change getCollectionInfo param from memory to calldata - Add @author natspec tag
…-merge Merges 5 new audit-fix commits from origin/issuance-audit: - TRST-R-1: reclaim pending rewards on stale allocation resize - TRST-R-2: improve reward documentation accuracy - TRST-R-3: remove redundant subgraphAllocatedTokens check - Rename NO_ALLOCATION to NO_ALLOCATED_TOKENS - Document minimumSubgraphSignal retroactive application Conflict resolution: - AllocationManager.sol: kept thin wrapper, passed maxPOIStaleness to AllocationHandler.resizeAllocation() - AllocationHandler.sol: ported stale reclaim logic (isStale check, reclaimRewards, clearPendingRewards) into resizeAllocation() - resize.t.sol: kept AllocationHandler import, added IAllocation import for new test assertions Auto-merged (verified): - MockRewardsManager.sol: realistic calcRewards/reclaimRewards - SubgraphService.t.sol: pending rewards assertion fix
Solhint already has func-name-mixedcase and var-name-mixedcase turned off. Align forge-lint by excluding these rules in horizon and subgraph-service to avoid redundant inline suppressions.
Cover pause/unpause access control, setPauseGuardian, and no-change revert cases.
Remove LibFixedMath, Denominations, DataServiceRescuable and its interface. None are imported by any source code in horizon or subgraph-service.
MathUtils only provided min() to horizon/subgraph-service code. The other two functions were unused. Switch to OZ's Math.min which is already a dependency, and delete the custom library.
Prevents forge lint from scanning into test/node_modules or other directories with incompatible dependencies or symlink loops.
- Add contract-level natspec to StakeClaims, IndexingAgreement, IndexingAgreementDecoder, IndexingAgreementDecoderRaw - Suppress gas-indexed-events on StakeClaims events and asm-keccak256 note - Move forge-lint comments before natspec blocks to fix natspec detection - Use block-style solhint-disable for function-max-lines suppression - Change struct params to calldata in AllocationHandler and IndexingAgreement - Remove orphaned natspec and unnecessary forge-lint comments
- Reorder AllocateParams struct to pack _delegationRatio (uint32) with _indexer (address) into a single 32-byte slot - Add forge-lint unsafe-typecast annotations in RecurringCollector with safety rationale for uint32/uint64 casts bounded by require checks
Pending indexing payments and post-Horizon contract changes
🚨 Report Summary
For more details view the full report in OpenZeppelin Code Inspector |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1288 +/- ##
==========================================
- Coverage 86.95% 86.80% -0.16%
==========================================
Files 46 46
Lines 2492 2485 -7
Branches 746 743 -3
==========================================
- Hits 2167 2157 -10
- Misses 325 328 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| mapping(address indexer => address destination) public override paymentsDestination; | ||
|
|
||
| /// @notice The cut data service takes from indexing fee payments. In PPM. | ||
| uint256 public indexingFeesCut; |
There was a problem hiding this comment.
This should be in SubgraphServiceV2Storage no?
There was a problem hiding this comment.
Yes, I thought about doing that but since we wanted minimum changes and the audit was done without SubgraphServiceV2Storage I left it unchanged.
|
Post-horizon clean up additions taken from #1261 and #1271 look good. Worth keeping this in context for this upgrade:
Related to 2), we actually need to revert that change, I'll do it shortly in a separate PR. |
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
|
#1291 addresses the changes mentioned in my previous comment, it also eliminates one of the assumptions:
|
feat: add back legacy allocation id collision check
Baseline of pending contract changes that need re-audit after rebasing to main.
For post-Horizon code cleanup to be valid these assumptions about the network must be true:
(Pending merge of #1291 to remove a previous assumption.)
This PR is likely to be split into two, and presented for audit processing in the following order (commits indicative but might need some adjusting):