Skip to content

Cancel agreements when indexers accept on-chain after rejecting off-chain#561

Merged
MoonBoi9001 merged 5 commits into
mainfrom
feat/560-chain-client
Feb 18, 2026
Merged

Cancel agreements when indexers accept on-chain after rejecting off-chain#561
MoonBoi9001 merged 5 commits into
mainfrom
feat/560-chain-client

Conversation

@MoonBoi9001

@MoonBoi9001 MoonBoi9001 commented Feb 18, 2026

Copy link
Copy Markdown
Member

Motivation

An indexer can reject a proposal off-chain while still accepting the same agreement on-chain before the deadline expires. This leaves Dipper with an active commitment to an indexer that already refused the work — with no way to undo it.

This PR adds the ability to cancel those agreements on-chain, freeing up the work to be reassigned.

Summary

  • RPC provider pool with automatic failover and rotation across multiple endpoints, ported from rewards-eligibility-oracle
  • Exponential backoff retry with retryable error detection
  • Gas estimation with configurable safety bounds (floor, ceiling, buffer multiplier)
  • EIP-1559 gas pricing with configurable multiplier and max price cap
  • Nonce management with conflict detection and automatic refresh
  • Conditional dispatch in main.rs: AlloyChainClient when config enabled, StubChainClient otherwise
  • 12 unit tests covering gas estimation, RPC rotation, backoff, nonce detection, and ABI encoding

Disabled by default. Enable via config:

{
  "chain_client": {
    "enabled": true,
    "providers": ["https://arb1.arbitrum.io/rpc"],
    "chain_id": 42161,
    "subgraph_service_address": "0x...",
    "gas_price_multiplier": 1.2,
    "max_gas_price_gwei": 100
  }
}

Closes #560

MoonBoi9001 and others added 2 commits February 17, 2026 20:39
… cancellation

Port battle-tested RPC client patterns from rewards-eligibility-oracle
to Rust for sending on-chain transactions. This enables the Dipper to
call cancelIndexingAgreementByPayer on the SubgraphService contract
when indexers fail to accept proposals.

Implementation:
- RPC provider pool with automatic failover and rotation
- Exponential backoff retry (1s, 2s, 4s... capped at 30s)
- Gas estimation with safety bounds (floor/ceiling/buffer)
- Nonce management with conflict detection and refresh
- EIP-1559 gas pricing with configurable multiplier and cap
- Conditional dispatch: AlloyChainClient when enabled, StubChainClient otherwise

Configuration (disabled by default):
- chain_client.enabled, providers, chain_id, subgraph_service_address
- Gas tuning: gas_price_multiplier, max_gas_price_gwei, gas_buffer_multiplier, gas_floor

Closes #560

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@MoonBoi9001 MoonBoi9001 marked this pull request as ready for review February 18, 2026 02:57
…red timeout

- Fix critical ABI mismatch: cancelIndexingAgreementByPayer takes bytes16
  not bytes32 (verified against SubgraphServiceExtension.sol)
- Encode agreement ID as FixedBytes<16> directly instead of padding to 32
- Add .from(signer.address()) to transaction request so gas estimation
  simulates the correct sender
- Replace hardcoded 30s send timeout with the configured request_timeout
- Expose request_timeout() getter on RpcProviderPool for send_transaction
- Remove unreachable dead code in execute() loop (safety check and
  fallthrough error path)
- Fix stale StubChainClient doc comment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@MoonBoi9001 MoonBoi9001 changed the title feat(chain-client): implement AlloyChainClient for on-chain agreement cancellation Cancel agreements when indexers accept on-chain after rejecting off-chain Feb 18, 2026
MoonBoi9001 and others added 2 commits February 18, 2026 14:05
ChainListenerConfig only queries a subgraph, it does not send
transactions. gas_price_multiplier and max_gas_price_gwei belong
on ChainClientConfig, where they are already defined and used.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
No code path inspects transaction receipts, so this variant
was never constructible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@MoonBoi9001

Copy link
Copy Markdown
Member Author

Merging to unblock future development.

@MoonBoi9001 MoonBoi9001 merged commit 2fa8dd1 into main Feb 18, 2026
7 checks passed
@MoonBoi9001 MoonBoi9001 deleted the feat/560-chain-client branch February 18, 2026 19:39
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.

Implement ChainClient for on-chain agreement cancellation

1 participant