From 6c38d4c089c511c1f82ec07504f231ae7247bec5 Mon Sep 17 00:00:00 2001 From: MoonBoi9001 Date: Wed, 11 Mar 2026 15:46:09 -0500 Subject: [PATCH 1/7] fix: add missing Ignition dependency for HorizonStaking deployment HorizonStaking's constructor extends GraphDirectory, which queries the Controller for GraphToken, EpochManager, RewardsManager, etc. These are registered by GraphPeripheryModule. Without an explicit `after` dependency, Ignition may schedule HorizonStaking before the periphery registrations, causing the constructor to read address(0) and revert with GraphDirectoryInvalidZeroAddress. Every other core module (GraphPayments, PaymentsEscrow, GraphTallyCollector, RecurringCollector) declares this dependency. HorizonStaking was the only outlier. Co-Authored-By: Claude Opus 4.6 --- packages/horizon/ignition/modules/core/HorizonStaking.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/horizon/ignition/modules/core/HorizonStaking.ts b/packages/horizon/ignition/modules/core/HorizonStaking.ts index a7bec9076..0a13e9123 100644 --- a/packages/horizon/ignition/modules/core/HorizonStaking.ts +++ b/packages/horizon/ignition/modules/core/HorizonStaking.ts @@ -15,12 +15,12 @@ export default buildModule('HorizonStaking', (m) => { const subgraphServiceAddress = m.getParameter('subgraphServiceAddress') const maxThawingPeriod = m.getParameter('maxThawingPeriod') - // Deploy HorizonStaking implementation + // Deploy HorizonStaking implementation - requires periphery and proxies to be registered in the controller const HorizonStakingImplementation = deployImplementation(m, { name: 'HorizonStaking', artifact: HorizonStakingArtifact, constructorArgs: [Controller, subgraphServiceAddress], - }) + }, { after: [GraphPeripheryModule, HorizonProxiesModule] }) // Upgrade proxy to implementation contract const HorizonStaking = upgradeGraphProxy(m, GraphProxyAdmin, HorizonStakingProxy, HorizonStakingImplementation, { From 986c1a6d0d76301f937075577bd21a6688ff4b0e Mon Sep 17 00:00:00 2001 From: Miguel de Elias Date: Wed, 25 Feb 2026 11:07:38 -0300 Subject: [PATCH 2/7] fix: add RecurringCollector to horizon contracts in toolshed --- packages/toolshed/src/deployments/horizon/contracts.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/toolshed/src/deployments/horizon/contracts.ts b/packages/toolshed/src/deployments/horizon/contracts.ts index bd852d5f0..8b6dea184 100644 --- a/packages/toolshed/src/deployments/horizon/contracts.ts +++ b/packages/toolshed/src/deployments/horizon/contracts.ts @@ -36,6 +36,7 @@ export const GraphHorizonContractNameList = [ 'GraphPayments', 'PaymentsEscrow', 'GraphTallyCollector', + 'RecurringCollector', ] as const export interface GraphHorizonContracts extends ContractList { From 51bbd8270919047152009ae5475d62a54693edf0 Mon Sep 17 00:00:00 2001 From: Miguel de Elias Date: Wed, 25 Feb 2026 16:34:02 -0300 Subject: [PATCH 3/7] feat: add RecurringCollector type and DIPs helpers to toolshed - Add IRecurringCollector to GraphHorizonContracts interface - Re-export IRecurringCollector from interfaces main entrypoint - Add encodeCollectIndexingFeesData() helper for indexing fee collection - Add decoders: decodeSignedRCA, decodeAcceptIndexingAgreementMetadata, decodeIndexingAgreementTermsV1 - Add round-trip tests for all decoders and encoder --- packages/interfaces/src/types/horizon.ts | 2 + .../toolshed/src/core/recurring-collector.ts | 84 +++++++++ .../toolshed/src/core/subgraph-service.ts | 15 ++ .../src/deployments/horizon/contracts.ts | 2 + .../toolshed/test/recurring-collector.test.ts | 176 ++++++++++++++++++ packages/toolshed/tsconfig.json | 3 +- 6 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 packages/toolshed/test/recurring-collector.test.ts diff --git a/packages/interfaces/src/types/horizon.ts b/packages/interfaces/src/types/horizon.ts index c2a09abb6..1208dd11d 100644 --- a/packages/interfaces/src/types/horizon.ts +++ b/packages/interfaces/src/types/horizon.ts @@ -10,6 +10,7 @@ import type { IL2GNSToolshed, ILegacyRewardsManager, IPaymentsEscrowToolshed, + IRecurringCollector, IRewardsManagerToolshed, IStaking, ISubgraphNFT, @@ -29,5 +30,6 @@ export { IStaking as LegacyStaking, IPaymentsEscrowToolshed as PaymentsEscrow, IRewardsManagerToolshed as RewardsManager, + IRecurringCollector, ISubgraphNFT as SubgraphNFT, } diff --git a/packages/toolshed/src/core/recurring-collector.ts b/packages/toolshed/src/core/recurring-collector.ts index 42c1bc7be..c9cc930c3 100644 --- a/packages/toolshed/src/core/recurring-collector.ts +++ b/packages/toolshed/src/core/recurring-collector.ts @@ -35,3 +35,87 @@ export const RC_EIP712_RCA_TYPESTRING = /** EIP-712 typestring for a RecurringCollectionAgreementUpdate (RCAU). */ export const RC_EIP712_RCAU_TYPESTRING = 'RecurringCollectionAgreementUpdate(bytes16 agreementId,uint64 deadline,uint64 endsAt,uint256 maxInitialTokens,uint256 maxOngoingTokensPerSecond,uint32 minSecondsPerCollection,uint32 maxSecondsPerCollection,uint16 conditions,uint32 nonce,bytes metadata)' + +import { BytesLike, ethers } from 'ethers' + +// -- ABI tuple types for decoding -- + +const RCA_TUPLE = + 'tuple(uint64 deadline, uint64 endsAt, address payer, address dataService, address serviceProvider, uint256 maxInitialTokens, uint256 maxOngoingTokensPerSecond, uint32 minSecondsPerCollection, uint32 maxSecondsPerCollection, uint256 nonce, bytes metadata)' + +const SIGNED_RCA_TUPLE = `tuple(${RCA_TUPLE} rca, bytes signature)` + +const ACCEPT_METADATA_TUPLE = 'tuple(bytes32 subgraphDeploymentId, uint8 version, bytes terms)' + +const TERMS_V1_TUPLE = 'tuple(uint256 tokensPerSecond, uint256 tokensPerEntityPerSecond)' + +// -- Return types -- + +export interface RecurringCollectionAgreement { + deadline: bigint + endsAt: bigint + payer: string + dataService: string + serviceProvider: string + maxInitialTokens: bigint + maxOngoingTokensPerSecond: bigint + minSecondsPerCollection: bigint + maxSecondsPerCollection: bigint + nonce: bigint + metadata: string +} + +export interface SignedRCA { + rca: RecurringCollectionAgreement + signature: string +} + +export interface AcceptIndexingAgreementMetadata { + subgraphDeploymentId: string + version: bigint + terms: string +} + +export interface IndexingAgreementTermsV1 { + tokensPerSecond: bigint + tokensPerEntityPerSecond: bigint +} + +// -- Decoders -- + +export function decodeSignedRCA(data: BytesLike): SignedRCA { + const [decoded] = ethers.AbiCoder.defaultAbiCoder().decode([SIGNED_RCA_TUPLE], data) + return { + rca: { + deadline: decoded.rca.deadline, + endsAt: decoded.rca.endsAt, + payer: decoded.rca.payer, + dataService: decoded.rca.dataService, + serviceProvider: decoded.rca.serviceProvider, + maxInitialTokens: decoded.rca.maxInitialTokens, + maxOngoingTokensPerSecond: decoded.rca.maxOngoingTokensPerSecond, + minSecondsPerCollection: decoded.rca.minSecondsPerCollection, + maxSecondsPerCollection: decoded.rca.maxSecondsPerCollection, + nonce: decoded.rca.nonce, + metadata: decoded.rca.metadata, + }, + signature: decoded.signature, + } +} + +export function decodeAcceptIndexingAgreementMetadata(data: BytesLike): AcceptIndexingAgreementMetadata { + const [decoded] = ethers.AbiCoder.defaultAbiCoder().decode([ACCEPT_METADATA_TUPLE], data) + return { + subgraphDeploymentId: decoded.subgraphDeploymentId, + version: decoded.version, + terms: decoded.terms, + } +} + +export function decodeIndexingAgreementTermsV1(data: BytesLike): IndexingAgreementTermsV1 { + const [decoded] = ethers.AbiCoder.defaultAbiCoder().decode([TERMS_V1_TUPLE], data) + return { + tokensPerSecond: decoded.tokensPerSecond, + tokensPerEntityPerSecond: decoded.tokensPerEntityPerSecond, + } +} diff --git a/packages/toolshed/src/core/subgraph-service.ts b/packages/toolshed/src/core/subgraph-service.ts index b4301900f..03a7840d0 100644 --- a/packages/toolshed/src/core/subgraph-service.ts +++ b/packages/toolshed/src/core/subgraph-service.ts @@ -32,6 +32,21 @@ export function encodeCollectQueryFeesData(rav: RAV, signature: string, tokensTo ) } +export function encodeCollectIndexingFeesData( + agreementId: string, + entities: bigint, + poi: BytesLike, + poiBlockNumber: bigint, + metadata: BytesLike, + maxSlippage: bigint, +) { + const innerData = ethers.AbiCoder.defaultAbiCoder().encode( + ['uint256', 'bytes32', 'uint256', 'bytes', 'uint256'], + [entities, poi, poiBlockNumber, metadata, maxSlippage], + ) + return ethers.AbiCoder.defaultAbiCoder().encode(['bytes16', 'bytes'], [agreementId, innerData]) +} + export function encodeStopServiceData(allocationId: string) { return ethers.AbiCoder.defaultAbiCoder().encode(['address'], [allocationId]) } diff --git a/packages/toolshed/src/deployments/horizon/contracts.ts b/packages/toolshed/src/deployments/horizon/contracts.ts index 8b6dea184..4221d9694 100644 --- a/packages/toolshed/src/deployments/horizon/contracts.ts +++ b/packages/toolshed/src/deployments/horizon/contracts.ts @@ -5,6 +5,7 @@ import type { GraphProxyAdmin, GraphTallyCollector, HorizonStaking, + IRecurringCollector, L2Curation, L2GNS, L2GraphToken, @@ -57,6 +58,7 @@ export interface GraphHorizonContracts extends ContractList Date: Wed, 15 Apr 2026 23:29:34 +0100 Subject: [PATCH 4/7] fix: link subgraph-service libraries in Ignition module The audit-branch SubgraphService.sol now depends on four external libraries (StakeClaims, AllocationHandler, IndexingAgreement, IndexingAgreementDecoder) and a fifth constructor argument for the RecurringCollector, but the Ignition deploy module was not updated to match. Deploys fail at validation time with IGN716 (missing libraries) and IGN703 (4 args expected 5), blocking any fresh hardhat deployment. Deploy the four libraries up-front via m.library() and pass them through deployImplementation's libraries option so the bytecode placeholders resolve. Thread the RecurringCollector address from the horizon deployment into the $global patch in deploy.ts, and add a recurringCollectorAddress placeholder to both the default and localNetwork protocol configs so Ignition can getParameter() it. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ignition/configs/protocol.default.json5 | 3 +- .../configs/protocol.localNetwork.json5 | 3 +- .../ignition/modules/SubgraphService.ts | 36 ++++++++++++++++--- packages/subgraph-service/tasks/deploy.ts | 1 + 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/subgraph-service/ignition/configs/protocol.default.json5 b/packages/subgraph-service/ignition/configs/protocol.default.json5 index aedf53531..b48120ee7 100644 --- a/packages/subgraph-service/ignition/configs/protocol.default.json5 +++ b/packages/subgraph-service/ignition/configs/protocol.default.json5 @@ -23,7 +23,8 @@ "disputeManagerProxyAdminAddress": "", "subgraphServiceProxyAddress": "", "subgraphServiceProxyAdminAddress": "", - "graphTallyCollectorAddress": "" + "graphTallyCollectorAddress": "", + "recurringCollectorAddress": "" }, "DisputeManager": { "disputePeriod": 2419200, diff --git a/packages/subgraph-service/ignition/configs/protocol.localNetwork.json5 b/packages/subgraph-service/ignition/configs/protocol.localNetwork.json5 index 1b35b18c1..978e56a61 100644 --- a/packages/subgraph-service/ignition/configs/protocol.localNetwork.json5 +++ b/packages/subgraph-service/ignition/configs/protocol.localNetwork.json5 @@ -23,7 +23,8 @@ "disputeManagerProxyAdminAddress": "", "subgraphServiceProxyAddress": "", "subgraphServiceProxyAdminAddress": "", - "graphTallyCollectorAddress": "" + "graphTallyCollectorAddress": "", + "recurringCollectorAddress": "" }, "DisputeManager": { "disputePeriod": 7200, // 2 hours = 7200 seconds diff --git a/packages/subgraph-service/ignition/modules/SubgraphService.ts b/packages/subgraph-service/ignition/modules/SubgraphService.ts index 8efb6800b..f1ae0382e 100644 --- a/packages/subgraph-service/ignition/modules/SubgraphService.ts +++ b/packages/subgraph-service/ignition/modules/SubgraphService.ts @@ -14,6 +14,7 @@ export default buildModule('SubgraphService', (m) => { const subgraphServiceProxyAdminAddress = m.getParameter('subgraphServiceProxyAdminAddress') const disputeManagerProxyAddress = m.getParameter('disputeManagerProxyAddress') const graphTallyCollectorAddress = m.getParameter('graphTallyCollectorAddress') + const recurringCollectorAddress = m.getParameter('recurringCollectorAddress') const curationProxyAddress = m.getParameter('curationProxyAddress') const minimumProvisionTokens = m.getParameter('minimumProvisionTokens') const maximumDelegationRatio = m.getParameter('maximumDelegationRatio') @@ -28,11 +29,38 @@ export default buildModule('SubgraphService', (m) => { subgraphServiceProxyAddress, ) + // Deploy libraries required by SubgraphService's audit-branch constructor. + // The contract has been refactored to pull allocation, stake-claim, and + // indexing-agreement logic into stand-alone libraries; these must be + // deployed and link-passed to the implementation so the bytecode's + // placeholder slots resolve at deploy time. + const StakeClaims = m.library('StakeClaims') + const AllocationHandler = m.library('AllocationHandler') + const IndexingAgreement = m.library('IndexingAgreement') + const IndexingAgreementDecoder = m.library('IndexingAgreementDecoder') + // Deploy implementation - const SubgraphServiceImplementation = deployImplementation(m, { - name: 'SubgraphService', - constructorArgs: [controllerAddress, disputeManagerProxyAddress, graphTallyCollectorAddress, curationProxyAddress], - }) + const SubgraphServiceImplementation = deployImplementation( + m, + { + name: 'SubgraphService', + constructorArgs: [ + controllerAddress, + disputeManagerProxyAddress, + graphTallyCollectorAddress, + curationProxyAddress, + recurringCollectorAddress, + ], + }, + { + libraries: { + StakeClaims, + AllocationHandler, + IndexingAgreement, + IndexingAgreementDecoder, + }, + }, + ) // Upgrade implementation const SubgraphService = upgradeTransparentUpgradeableProxy( diff --git a/packages/subgraph-service/tasks/deploy.ts b/packages/subgraph-service/tasks/deploy.ts index 581138439..860e8c67b 100644 --- a/packages/subgraph-service/tasks/deploy.ts +++ b/packages/subgraph-service/tasks/deploy.ts @@ -91,6 +91,7 @@ task('deploy:protocol', 'Deploy a new version of the Graph Protocol Horizon cont subgraphServiceProxyAddress: proxiesDeployment.Transparent_Proxy_SubgraphService.target as string, subgraphServiceProxyAdminAddress: proxiesDeployment.Transparent_ProxyAdmin_SubgraphService.target as string, graphTallyCollectorAddress: horizonDeployment.GraphTallyCollector.target as string, + recurringCollectorAddress: horizonDeployment.Transparent_Proxy_RecurringCollector.target as string, gnsProxyAddress: horizonDeployment.Graph_Proxy_L2GNS.target as string, gnsImplementationAddress: horizonDeployment.Implementation_L2GNS.target as string, subgraphNFTAddress: horizonDeployment.SubgraphNFT.target as string, From d217c9c09573b478176c24799dcddb7b752284e2 Mon Sep 17 00:00:00 2001 From: MoonBoi9001 Date: Thu, 16 Apr 2026 00:07:42 +0100 Subject: [PATCH 5/7] fix: link transitive library deps for IndexingAgreement stack Ignition's validator walks each deployed library's bytecode, so it is not enough to link the four libraries into SubgraphService and stop there. IndexingAgreement calls into IndexingAgreementDecoder, which calls into IndexingAgreementDecoderRaw, so both transitive links have to be declared up-front or the deploy aborts on IGN716 while validating the library futures themselves. Deploy IndexingAgreementDecoderRaw first, link it into the Decoder, and link the Decoder into IndexingAgreement. SubgraphService keeps its existing four links unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ignition/modules/SubgraphService.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/subgraph-service/ignition/modules/SubgraphService.ts b/packages/subgraph-service/ignition/modules/SubgraphService.ts index f1ae0382e..5b52706ba 100644 --- a/packages/subgraph-service/ignition/modules/SubgraphService.ts +++ b/packages/subgraph-service/ignition/modules/SubgraphService.ts @@ -34,10 +34,23 @@ export default buildModule('SubgraphService', (m) => { // indexing-agreement logic into stand-alone libraries; these must be // deployed and link-passed to the implementation so the bytecode's // placeholder slots resolve at deploy time. + // + // Ordering matters: IndexingAgreement calls into IndexingAgreementDecoder, + // which in turn calls into IndexingAgreementDecoderRaw, so the deeper + // libraries have to be deployed and linked first. const StakeClaims = m.library('StakeClaims') const AllocationHandler = m.library('AllocationHandler') - const IndexingAgreement = m.library('IndexingAgreement') - const IndexingAgreementDecoder = m.library('IndexingAgreementDecoder') + const IndexingAgreementDecoderRaw = m.library('IndexingAgreementDecoderRaw') + const IndexingAgreementDecoder = m.library('IndexingAgreementDecoder', { + libraries: { + IndexingAgreementDecoderRaw, + }, + }) + const IndexingAgreement = m.library('IndexingAgreement', { + libraries: { + IndexingAgreementDecoder, + }, + }) // Deploy implementation const SubgraphServiceImplementation = deployImplementation( From 9f219a75ceaea81ff2ff3bb8720705ed15e388a8 Mon Sep 17 00:00:00 2001 From: MoonBoi9001 Date: Thu, 16 Apr 2026 18:13:38 +0100 Subject: [PATCH 6/7] fix(toolshed): add conditions field to RCA decoder tuple The audit-branch RecurringCollectionAgreement struct added a uint16 conditions field at position 9 (between maxSecondsPerCollection and nonce). The toolshed decoder tuple was missing it, so decodeSignedRCA read 10 fields against 11 ABI-encoded fields: nonce read what was actually conditions, metadata read the wrong offset, decode threw. The indexer-agent relies on this decoder to read pending RCA proposals the indexer-service persists. Without the fix, every proposal logs "Failed to decode pending RCA proposal" and is skipped, so the agent never calls acceptIndexingAgreement on-chain and DIPs agreements expire in dipper's DB. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/toolshed/src/core/recurring-collector.ts | 4 +++- packages/toolshed/test/recurring-collector.test.ts | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/toolshed/src/core/recurring-collector.ts b/packages/toolshed/src/core/recurring-collector.ts index c9cc930c3..0867c6499 100644 --- a/packages/toolshed/src/core/recurring-collector.ts +++ b/packages/toolshed/src/core/recurring-collector.ts @@ -41,7 +41,7 @@ import { BytesLike, ethers } from 'ethers' // -- ABI tuple types for decoding -- const RCA_TUPLE = - 'tuple(uint64 deadline, uint64 endsAt, address payer, address dataService, address serviceProvider, uint256 maxInitialTokens, uint256 maxOngoingTokensPerSecond, uint32 minSecondsPerCollection, uint32 maxSecondsPerCollection, uint256 nonce, bytes metadata)' + 'tuple(uint64 deadline, uint64 endsAt, address payer, address dataService, address serviceProvider, uint256 maxInitialTokens, uint256 maxOngoingTokensPerSecond, uint32 minSecondsPerCollection, uint32 maxSecondsPerCollection, uint16 conditions, uint256 nonce, bytes metadata)' const SIGNED_RCA_TUPLE = `tuple(${RCA_TUPLE} rca, bytes signature)` @@ -61,6 +61,7 @@ export interface RecurringCollectionAgreement { maxOngoingTokensPerSecond: bigint minSecondsPerCollection: bigint maxSecondsPerCollection: bigint + conditions: bigint nonce: bigint metadata: string } @@ -96,6 +97,7 @@ export function decodeSignedRCA(data: BytesLike): SignedRCA { maxOngoingTokensPerSecond: decoded.rca.maxOngoingTokensPerSecond, minSecondsPerCollection: decoded.rca.minSecondsPerCollection, maxSecondsPerCollection: decoded.rca.maxSecondsPerCollection, + conditions: decoded.rca.conditions, nonce: decoded.rca.nonce, metadata: decoded.rca.metadata, }, diff --git a/packages/toolshed/test/recurring-collector.test.ts b/packages/toolshed/test/recurring-collector.test.ts index 51c28b509..1bbc9ceb5 100644 --- a/packages/toolshed/test/recurring-collector.test.ts +++ b/packages/toolshed/test/recurring-collector.test.ts @@ -23,6 +23,7 @@ const coder = ethers.AbiCoder.defaultAbiCoder() maxOngoingTokensPerSecond: 1n * 10n ** 15n, minSecondsPerCollection: 3600n, maxSecondsPerCollection: 86400n, + conditions: 0n, nonce: 42n, metadata: '0xdeadbeef', } @@ -30,7 +31,7 @@ const coder = ethers.AbiCoder.defaultAbiCoder() const encoded = coder.encode( [ - 'tuple(tuple(uint64 deadline, uint64 endsAt, address payer, address dataService, address serviceProvider, uint256 maxInitialTokens, uint256 maxOngoingTokensPerSecond, uint32 minSecondsPerCollection, uint32 maxSecondsPerCollection, uint256 nonce, bytes metadata) rca, bytes signature)', + 'tuple(tuple(uint64 deadline, uint64 endsAt, address payer, address dataService, address serviceProvider, uint256 maxInitialTokens, uint256 maxOngoingTokensPerSecond, uint32 minSecondsPerCollection, uint32 maxSecondsPerCollection, uint16 conditions, uint256 nonce, bytes metadata) rca, bytes signature)', ], [{ rca, signature }], ) @@ -46,6 +47,7 @@ const coder = ethers.AbiCoder.defaultAbiCoder() assert.equal(decoded.rca.maxOngoingTokensPerSecond, rca.maxOngoingTokensPerSecond) assert.equal(decoded.rca.minSecondsPerCollection, rca.minSecondsPerCollection) assert.equal(decoded.rca.maxSecondsPerCollection, rca.maxSecondsPerCollection) + assert.equal(decoded.rca.conditions, rca.conditions) assert.equal(decoded.rca.nonce, rca.nonce) assert.equal(decoded.rca.metadata, rca.metadata) assert.equal(decoded.signature, signature) @@ -65,6 +67,7 @@ const coder = ethers.AbiCoder.defaultAbiCoder() maxOngoingTokensPerSecond: 0n, minSecondsPerCollection: 0n, maxSecondsPerCollection: 0n, + conditions: 0n, nonce: 0n, metadata: '0x', } @@ -72,7 +75,7 @@ const coder = ethers.AbiCoder.defaultAbiCoder() const encoded = coder.encode( [ - 'tuple(tuple(uint64 deadline, uint64 endsAt, address payer, address dataService, address serviceProvider, uint256 maxInitialTokens, uint256 maxOngoingTokensPerSecond, uint32 minSecondsPerCollection, uint32 maxSecondsPerCollection, uint256 nonce, bytes metadata) rca, bytes signature)', + 'tuple(tuple(uint64 deadline, uint64 endsAt, address payer, address dataService, address serviceProvider, uint256 maxInitialTokens, uint256 maxOngoingTokensPerSecond, uint32 minSecondsPerCollection, uint32 maxSecondsPerCollection, uint16 conditions, uint256 nonce, bytes metadata) rca, bytes signature)', ], [{ rca, signature }], ) From 36c70b1a3e75fbc974eba9b37248495cdbef377d Mon Sep 17 00:00:00 2001 From: MoonBoi9001 Date: Thu, 7 May 2026 19:10:11 +0800 Subject: [PATCH 7/7] style(lint): autofix imports, exports, and formatting Run eslint --fix and prettier --write on the files introduced by the cherry-picked toolshed and ignition work, restoring the project's required import/export order and multi-line argument layout. --- .../ignition/modules/core/HorizonStaking.ts | 14 +++++++++----- packages/interfaces/src/types/horizon.ts | 2 +- packages/toolshed/test/recurring-collector.test.ts | 8 ++++++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/horizon/ignition/modules/core/HorizonStaking.ts b/packages/horizon/ignition/modules/core/HorizonStaking.ts index 0a13e9123..ec98c1066 100644 --- a/packages/horizon/ignition/modules/core/HorizonStaking.ts +++ b/packages/horizon/ignition/modules/core/HorizonStaking.ts @@ -16,11 +16,15 @@ export default buildModule('HorizonStaking', (m) => { const maxThawingPeriod = m.getParameter('maxThawingPeriod') // Deploy HorizonStaking implementation - requires periphery and proxies to be registered in the controller - const HorizonStakingImplementation = deployImplementation(m, { - name: 'HorizonStaking', - artifact: HorizonStakingArtifact, - constructorArgs: [Controller, subgraphServiceAddress], - }, { after: [GraphPeripheryModule, HorizonProxiesModule] }) + const HorizonStakingImplementation = deployImplementation( + m, + { + name: 'HorizonStaking', + artifact: HorizonStakingArtifact, + constructorArgs: [Controller, subgraphServiceAddress], + }, + { after: [GraphPeripheryModule, HorizonProxiesModule] }, + ) // Upgrade proxy to implementation contract const HorizonStaking = upgradeGraphProxy(m, GraphProxyAdmin, HorizonStakingProxy, HorizonStakingImplementation, { diff --git a/packages/interfaces/src/types/horizon.ts b/packages/interfaces/src/types/horizon.ts index 1208dd11d..95b656958 100644 --- a/packages/interfaces/src/types/horizon.ts +++ b/packages/interfaces/src/types/horizon.ts @@ -23,6 +23,7 @@ export { IGraphProxyAdmin as GraphProxyAdmin, IGraphTallyCollectorToolshed as GraphTallyCollector, IHorizonStakingToolshed as HorizonStaking, + IRecurringCollector, IL2CurationToolshed as L2Curation, IL2GNSToolshed as L2GNS, IGraphToken as L2GraphToken, @@ -30,6 +31,5 @@ export { IStaking as LegacyStaking, IPaymentsEscrowToolshed as PaymentsEscrow, IRewardsManagerToolshed as RewardsManager, - IRecurringCollector, ISubgraphNFT as SubgraphNFT, } diff --git a/packages/toolshed/test/recurring-collector.test.ts b/packages/toolshed/test/recurring-collector.test.ts index 1bbc9ceb5..9a8e7efd7 100644 --- a/packages/toolshed/test/recurring-collector.test.ts +++ b/packages/toolshed/test/recurring-collector.test.ts @@ -1,10 +1,11 @@ import assert from 'node:assert/strict' + import { ethers } from 'ethers' import { - decodeSignedRCA, decodeAcceptIndexingAgreementMetadata, decodeIndexingAgreementTermsV1, + decodeSignedRCA, encodeCollectIndexingFeesData, } from '../dist/core/index.js' @@ -138,7 +139,10 @@ const coder = ethers.AbiCoder.defaultAbiCoder() const tokensPerSecond = 1000n * 10n ** 18n const tokensPerEntityPerSecond = 5n * 10n ** 15n - const encoded = coder.encode(['tuple(uint256 tokensPerSecond, uint256 tokensPerEntityPerSecond)'], [{ tokensPerSecond, tokensPerEntityPerSecond }]) + const encoded = coder.encode( + ['tuple(uint256 tokensPerSecond, uint256 tokensPerEntityPerSecond)'], + [{ tokensPerSecond, tokensPerEntityPerSecond }], + ) const decoded = decodeIndexingAgreementTermsV1(encoded)