diff --git a/docs/errors.md b/docs/errors.md index 23d573bd6..3cba9066e 100644 --- a/docs/errors.md +++ b/docs/errors.md @@ -887,3 +887,17 @@ This is a sub-error of `IE069`. It is reported when the indexer agent doesn't ha **Solution** Please provide a `epoch-subgraph-endpoint` and make sure graph node has consistent network configurations (`mainnet`, `sepolia`, `gnosis`) and is on or after version 0.28.0. + +## IE090 + +**Summary** + +Failed to collect indexing rewards: indexer not eligible for rewards. + +**Description** + +The `collect` call for indexing rewards reverted because the indexer is currently ineligible for rewards, as determined by the rewards eligibility oracle. The revert happens at gas estimation, so no transaction is broadcast and no gas is spent; the indexer agent does not retry within the call, but the reconciliation loop will attempt the collect again on a later cycle. + +**Solution** + +No operator action is required if ineligibility is expected to clear: once the indexer becomes eligible again, a subsequent collect will succeed and the rewards remain claimable until the allocation goes stale. If the indexer is unexpectedly ineligible, investigate the rewards eligibility oracle status for this indexer address. The allocation can also still be closed without collecting rewards by presenting a zero POI (`0x0`). diff --git a/packages/indexer-common/src/errors.ts b/packages/indexer-common/src/errors.ts index 0b1c0ddbd..518ed4e0e 100644 --- a/packages/indexer-common/src/errors.ts +++ b/packages/indexer-common/src/errors.ts @@ -100,6 +100,7 @@ export enum IndexerErrorCode { IE087 = 'IE087', IE088 = 'IE088', IE089 = 'IE089', + IE090 = 'IE090', } export const INDEXER_ERROR_MESSAGES: Record = { @@ -193,6 +194,7 @@ export const INDEXER_ERROR_MESSAGES: Record = { IE087: 'Failed to resize allocation', IE088: 'Failed to present POI', IE089: 'Failed to collect indexing rewards', + IE090: 'Failed to collect indexing rewards: indexer not eligible for rewards', } export type IndexerErrorCause = unknown diff --git a/packages/indexer-common/src/indexer-management/resolvers/allocations.ts b/packages/indexer-common/src/indexer-management/resolvers/allocations.ts index d1c26cdc9..fe8eade19 100644 --- a/packages/indexer-common/src/indexer-management/resolvers/allocations.ts +++ b/packages/indexer-common/src/indexer-management/resolvers/allocations.ts @@ -469,6 +469,24 @@ async function createAllocation( /** * Execute collect transaction for indexing rewards */ +// RewardsManager reverts with this string `require` when the indexer is +// ineligible for rewards and `revertOnIneligible` is enabled on-chain. +const INDEXER_INELIGIBLE_REVERT = 'Indexer not eligible for rewards' + +function isIndexerIneligibleRevert(error: unknown): boolean { + if (!error || typeof error !== 'object') { + return false + } + const { reason, shortMessage, message } = error as { + reason?: unknown + shortMessage?: unknown + message?: unknown + } + return [reason, shortMessage, message].some( + (field) => typeof field === 'string' && field.includes(INDEXER_INELIGIBLE_REVERT), + ) +} + async function executeCollectTransaction( network: Network, allocationId: string, @@ -479,22 +497,33 @@ async function executeCollectTransaction( const transactionManager = network.transactionManager const address = network.specification.indexerOptions.address - const receipt = await transactionManager.executeTransaction( - async () => - contracts.SubgraphService.collect.estimateGas( - address, - PaymentTypes.IndexingRewards, - collectData, - ), - async (gasLimit) => - contracts.SubgraphService.collect( - address, - PaymentTypes.IndexingRewards, - collectData, - { gasLimit }, - ), - logger, - ) + let receipt: TransactionReceipt | 'paused' | 'unauthorized' + try { + receipt = await transactionManager.executeTransaction( + async () => + contracts.SubgraphService.collect.estimateGas( + address, + PaymentTypes.IndexingRewards, + collectData, + ), + async (gasLimit) => + contracts.SubgraphService.collect( + address, + PaymentTypes.IndexingRewards, + collectData, + { gasLimit }, + ), + logger, + ) + } catch (error) { + if (isIndexerIneligibleRevert(error)) { + throw indexerError( + IndexerErrorCode.IE090, + `Collect indexing rewards for allocation '${allocationId}' reverted: indexer not eligible for rewards`, + ) + } + throw error + } if (receipt === 'paused' || receipt === 'unauthorized') { throw indexerError(