Summary
Wire the reth-erc8004-indexer into obol network install ethereum --mode archive as a drop-in reth image swap with ERC-8004 ExEx indexing, plus a 3-tier discovery client for downstream consumers (autoresearch, etc.).
Context
The reth-erc8004-indexer was extracted from PR #288 (Oisin's review: standalone Rust, not wired into the stack). The binary is compiled as reth ([[bin]] name = "reth" in Cargo.toml) — it IS reth with an ExEx bolted on. This means it's a drop-in image swap in the existing ethereum-helm-charts/ethereum-node chart, not a separate Helm chart.
Design
When --execution-client reth --mode archive is specified, the helmfile swaps the upstream ethereum/reth image for ghcr.io/obolnetwork/reth-erc8004-indexer, exposes the indexer API port (3400), and adds a SQLite PVC.
obol network install ethereum --mode archive
|
+-- executionClient: reth (default)
+-- mode: archive
|
+-- helmfile renders:
reth:
image:
repository: ghcr.io/obolnetwork/reth-erc8004-indexer
tag: v0.1.0
extraPorts:
- name: indexer-api
containerPort: 3400
CLI behavior
# Default (unchanged)
obol network install ethereum
# -> reth full sync, no indexer
# Archive mode with ERC-8004 indexing
obol network install ethereum --mode archive
# -> reth-erc8004-indexer image, ExEx enabled, API on :3400
# Archive + non-reth client (indexer N/A)
obol network install ethereum --mode archive --execution-client geth
# -> geth archive sync, no indexer (warn: ERC-8004 indexing only with reth)
Implementation Phases
Phase 1: Template plumbing (unblocks everything)
| File |
Change |
internal/embed/networks/ethereum/values.yaml.gotmpl |
Add Mode field: @enum full,archive @default full |
internal/embed/networks/ethereum/helmfile.yaml.gotmpl |
Conditional image swap when mode=archive + executionClient=reth |
internal/embed/networks/ethereum/templates/pvc.yaml |
Optional indexer PVC (indexer-data, 10Gi) when archive mode |
CLI --mode flag is auto-generated from the @enum annotation -- zero Go code needed.
Phase 2: Indexer image CI (parallel)
| File |
Change |
reth-erc8004-indexer/ |
Restore Rust source from extracted commit |
Dockerfile.reth-erc8004-indexer |
Restore |
.github/workflows/docker-publish-reth-indexer.yml |
Build + publish + Trivy scan |
Phase 3: Discovery client (parallel)
| File |
Change |
internal/discovery/discovery.go |
DiscoveryClient interface + FallbackClient |
internal/discovery/reth.go |
Client for local indexer API (:3400) |
internal/discovery/basescan.go |
Client for BaseScan ERC-8004 metadata |
internal/discovery/eightkcan.go |
Client for 8004scan.io |
internal/discovery/*_test.go |
Per-client unit + fallback integration tests |
Phase 4: Wire into autoresearch
- Auto-detect indexer when deployed (archive mode)
- Fallback: no indexer -> BaseScan -> 8004scan.io
- Integration test: register -> index -> discover -> probe via x402
Dependency graph
Phase 1 (template) --+
Phase 2 (CI) --+--> Phase 4 (wire autoresearch)
Phase 3 (discovery) -+
Phases 1, 2, 3 run in parallel.
3-Tier Discovery Architecture
Priority 1: Internal Reth Indexer (self-hosted, real-time)
| reth-indexer:3400
| Latency: <100ms, block-level freshness
| Cost: runs archive Base L2 node (~500GB disk)
v if unavailable
Priority 2: BaseScan API (hosted, reliable)
| api.basescan.org -- ERC-8004 metadata natively supported
| Latency: <500ms, free tier 5 calls/sec
v if no API key
Priority 3: 8004scan.io (community, best-effort)
| No key required, minutes behind chain
v if all unavailable
Error: no discovery backend
Discovery Client Interface
type DiscoveryClient interface {
ListAgents(ctx context.Context, opts ListOptions) ([]Agent, error)
SearchAgents(ctx context.Context, query string, limit int) ([]Agent, error)
GetAgent(ctx context.Context, chainID uint64, tokenID string) (*Agent, error)
Health(ctx context.Context) error
}
Test Plan
Rust unit tests
storage.rs: SQLite CRUD, pagination, search
indexer.rs: event log parsing, reorg handling
api.rs: response shape matches 8004scan contract
Go tests
- Discovery client per-tier unit tests
- FallbackClient integration (priority order, cache TTL)
- Template rendering:
--mode archive produces correct image/port/PVC
Helm tests
test-api.yaml: health + stats endpoints
Integration
- Register agent on-chain -> indexer picks up -> coordinator discovers -> x402 probe
Acceptance Criteria
obol network install ethereum --mode archive deploys reth-erc8004-indexer image
- Indexer API serves on
:3400 with 8004scan-compatible responses
obol network install ethereum (no --mode) unchanged -- upstream reth image
- Discovery fallback works: indexer -> BaseScan -> 8004scan
- CI builds and publishes indexer image to ghcr.io
Summary
Wire the
reth-erc8004-indexerintoobol network install ethereum --mode archiveas a drop-in reth image swap with ERC-8004 ExEx indexing, plus a 3-tier discovery client for downstream consumers (autoresearch, etc.).Context
The reth-erc8004-indexer was extracted from PR #288 (Oisin's review: standalone Rust, not wired into the stack). The binary is compiled as
reth([[bin]] name = "reth"in Cargo.toml) — it IS reth with an ExEx bolted on. This means it's a drop-in image swap in the existingethereum-helm-charts/ethereum-nodechart, not a separate Helm chart.Design
When
--execution-client reth --mode archiveis specified, the helmfile swaps the upstreamethereum/rethimage forghcr.io/obolnetwork/reth-erc8004-indexer, exposes the indexer API port (3400), and adds a SQLite PVC.CLI behavior
Implementation Phases
Phase 1: Template plumbing (unblocks everything)
internal/embed/networks/ethereum/values.yaml.gotmplModefield:@enum full,archive @default fullinternal/embed/networks/ethereum/helmfile.yaml.gotmplmode=archive+executionClient=rethinternal/embed/networks/ethereum/templates/pvc.yamlindexer-data, 10Gi) when archive modeCLI
--modeflag is auto-generated from the@enumannotation -- zero Go code needed.Phase 2: Indexer image CI (parallel)
reth-erc8004-indexer/Dockerfile.reth-erc8004-indexer.github/workflows/docker-publish-reth-indexer.ymlPhase 3: Discovery client (parallel)
internal/discovery/discovery.goDiscoveryClientinterface +FallbackClientinternal/discovery/reth.go:3400)internal/discovery/basescan.gointernal/discovery/eightkcan.gointernal/discovery/*_test.goPhase 4: Wire into autoresearch
Dependency graph
Phases 1, 2, 3 run in parallel.
3-Tier Discovery Architecture
Discovery Client Interface
Test Plan
Rust unit tests
storage.rs: SQLite CRUD, pagination, searchindexer.rs: event log parsing, reorg handlingapi.rs: response shape matches 8004scan contractGo tests
--mode archiveproduces correct image/port/PVCHelm tests
test-api.yaml: health + stats endpointsIntegration
Acceptance Criteria
obol network install ethereum --mode archivedeploys reth-erc8004-indexer image:3400with 8004scan-compatible responsesobol network install ethereum(no --mode) unchanged -- upstream reth image