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
Both the Dipper and indexer-rs sides of this feature are now complete. The remaining work is contract deployment and the indexer agent's on-chain acceptance implementation, both of which are outside these two codebases.
This issue tracked the migration from the epoch-based `IndexingAgreementVoucher` to the seconds-based `RecurringCollectionAgreement` (RCA) — the same type the contract consumes — and the end-to-end on-chain acceptance flow.
Architecture
The Dipper signs an RCA with a short deadline (~5 min) and sends it to indexer-rs via gRPC (fire-and-forget, no off-chain ACCEPT/REJECT). The indexer agent picks it up, validates, ensures an allocation, and calls `SubgraphService.acceptIndexingAgreement(allocationId, signedRCA)` on-chain. The Dipper monitors for the `IndexingAgreementAccepted` event and transitions the agreement to `AcceptedOnChain`. If the deadline passes with no on-chain acceptance, the Dipper expires the agreement and reassigns it.
If an indexer rejects the proposal off-chain but accepts on-chain anyway, the chain listener detects this and Dipper cancels the active agreement via `cancelIndexingAgreementByPayer`.
Created -> AcceptedOnChain (on-chain event observed)
Created -> Expired (deadline passed, no on-chain acceptance)
Created -> DeliveryFailed (gRPC error sending to indexer-rs)
AcceptedOnChain -> CanceledByRequester (Dipper cancels adversarial on-chain acceptance)
AcceptedOnChain -> CanceledByIndexer (indexer cancels on-chain)
Phases
Phase 1 - Dipper: Status cleanup -- Remove `Accepted` and `Rejected` statuses. `Created` is the only pre-confirmation active status, `AcceptedOnChain` is the confirmed one. Update active agreement queries, unique constraint, replace `at_epoch` with timestamp. (97af12b, PR feat: periodic reassignment, V2 status cleanup, and AcceptedOnChain (#550) #553)
Phase 3 - Dipper: Sign and send SignedRCA -- Replace voucher signing with RCA signing using the contract's EIP-712 domain. Fire-and-forget gRPC call. ABI-encode `AcceptIndexingAgreementMetadata` into the RCA metadata field. Configurable deadline (~5 min). (22a648e, PR feat: migrate from epoch-based voucher to seconds-based RCA #555)
Phase 4 - indexer-rs: Store SignedRCA -- Simplified gRPC endpoint stores the `SignedRCA` blob in `pending_rca_proposals` with idempotent writes. Agent queries this table to pick up pending agreements. (indexer-rs PRs #942, #947, #948)
Phase 5 - Indexer agent: On-chain acceptance -- New `AgreementAcceptor` background service (follows TapCollector pattern). Read pending agreements from indexer-rs DB, validate terms, ensure allocation, call `SubgraphService.acceptIndexingAgreement()`. Blocked on Phase 6.
Phase 6 - Contract deployment -- The `IndexingAgreement.sol` contract has not been deployed yet. It needs to be deployed to Arbitrum Sepolia for testnet integration first, then to Arbitrum mainnet. Phases 5 and 7 depend on the contract being live.
Phase 7 - Protocol subgraph: Create and deploy -- No subgraph currently exists that indexes the `IndexingAgreement.sol` contract events. A new subgraph needs to be written, covering `IndexingAgreementAccepted`, `IndexingAgreementCanceled`, and `IndexingFeesCollectedV1` events emitted by the SubgraphService contract. Once the contract is deployed, the subgraph can be published and indexed. This is a prerequisite for Phase 8.
Context
Both the Dipper and indexer-rs sides of this feature are now complete. The remaining work is contract deployment and the indexer agent's on-chain acceptance implementation, both of which are outside these two codebases.
This issue tracked the migration from the epoch-based `IndexingAgreementVoucher` to the seconds-based `RecurringCollectionAgreement` (RCA) — the same type the contract consumes — and the end-to-end on-chain acceptance flow.
Architecture
The Dipper signs an RCA with a short deadline (~5 min) and sends it to indexer-rs via gRPC (fire-and-forget, no off-chain ACCEPT/REJECT). The indexer agent picks it up, validates, ensures an allocation, and calls `SubgraphService.acceptIndexingAgreement(allocationId, signedRCA)` on-chain. The Dipper monitors for the `IndexingAgreementAccepted` event and transitions the agreement to `AcceptedOnChain`. If the deadline passes with no on-chain acceptance, the Dipper expires the agreement and reassigns it.
If an indexer rejects the proposal off-chain but accepts on-chain anyway, the chain listener detects this and Dipper cancels the active agreement via `cancelIndexingAgreementByPayer`.
Agreement status flow:
Phases