In Scope (MVP):
-
Light version of ff-indexer supporting Ethereum (ERC-721/1155) and Tezos (FA2).
-
Derive token ownership and provenance exclusively from on-chain data.
-
Use 3rd-party APIs (OpenSea, Objkt, ArtBlocks, etc.) only for metadata enrichment, never for ownership or provenance.
-
Parse token metadata from on-chain URIs following:
- Ethereum: OpenSea Metadata Standard.
- Tezos: TZIP-21 for metadata schema.
-
Expose both REST and GraphQL interfaces.
-
Provide minimal operational endpoints for health and metrics.
Out of Scope:
- Bitmark blockchain.
- Historical sales or pricing data.
- Series registry and collection indexing.
- Any internal Bitmark-only service dependency.
Ownership
-
Ownership must match canonical blockchain data.
-
Ethereum:
- ERC-721: derive from
Transferevents. - ERC-1155: derive from
TransferSingle/TransferBatchevents; ownership based on positive balances.
- ERC-721: derive from
-
Tezos:
- FA2 (TZIP-12): derive from contract ledger entries and transfer entrypoints.
-
Burned tokens must be correctly recognized and marked.
Provenance
- Provenance must include chain-derived events:
Mint,Transfer,Burn, and metadata updates. - Provenance entries include at minimum: transaction hash, block/level, timestamp, and participant addresses.
- Support EIP-4906 (Ethereum) and metadata URI change detection (Tezos) for metadata update events.
Metadata Parsing
- Metadata URI fetched from contract-defined fields (e.g., ERC-721
tokenURI, FA2/TZIP-21metadatafield). - Parsed fields should align with OpenSea and TZIP-21 schemas.
- If metadata is incomplete, attempt enrichment via 3rd-party APIs, but never override on-chain truth.
- Metadata enrichment must be flagged with a provenance source label.
On-Demand Indexing
- Must support on-demand indexing of individual tokens or all tokens owned by given addresses.
- Must be idempotent.
Automatic Refresh
- Token ownership and provenance refresh triggered by new blocks/levels.
- Metadata refresh only when URI changes, a metadata update event is detected, or TTL expires.
Reorganization Handling (Optional)
- On-chain reorgs must trigger recomputation of affected ownership and provenance data.
The service must expose the following endpoints (both REST and GraphQL equivalents):
-
GET
/api/v1/tokens/:idRetrieve a specific token by its canonical ID. Must return accurate, normalized data reflecting current chain state. -
GET
/api/v1/tokensRetrieve tokens owned by one or more addresses. Must support sorting bylastActivityTimeand pagination. -
POST
/api/v1/tokensTrigger indexing for specific tokens or owners. Must return job information and handle idempotency. -
GET
/api/v1/changesQuery recent changes within a timeframe. Must support filters:owners(repeatable): wallet addresses.since: RFC3339 timestamp.tokenIDs: optional filter for specific tokens. The endpoint should return all tokens that have changed (ownership, metadata, or provenance) since the specified timestamp. This endpoint enables incremental sync and efficient caching for clients.
- GET
/healthzfor liveness checks. - GET
/readyzfor readiness. (OPTIONAL) - GET
/metricsfor Prometheus-compatible metrics. (OPTIONAL)
- P95 latency for reads (
GET /tokens) < 600ms for cached responses. - Address indexing (100–300 tokens/wallet) completes within 30s P95.
- Minimum 99% availability over 24 hours.
Resilience Requirements:
- Circuit breakers for all 3rd-party enrichment adapters.
- Retry with exponential backoff on transient errors.
- Failed enrichment must not block ownership indexing.
Observability:
- Expose tracing (trace IDs), structured logs, and metrics for all major operations.
- Dashboards must report indexing backlog, vendor failure rates, and request latencies.
Unit Tests:
- Ownership derivation for ERC-721, ERC-1155, and FA2 contracts.
- Provenance construction from chain events.
- Metadata parsing for OpenSea and TZIP-21 formats.
- Enrichment logic ensuring no override of chain truth.
Integration Tests:
- Full wallet indexing covering mixed ERC-721/1155/FA2 assets.
- Reorg simulation with state recovery.
- Metadata URI changes triggering update events.
Contract Tests (OPTIONAL):
- REST and GraphQL parity for responses.
- Pagination and sorting consistency by
lastActivityTime.
Operational Tests (OPTIONAL):
- Health and readiness probes functional.
- Metrics exported and monitored.
Definition of Done:
- All tests pass in CI with >80% coverage on core modules.
- Service meets performance SLOs and stability targets in staging.
- Deployment verified with real wallets and testnets for both chains.
- Documentation (OpenAPI + GraphQL schema) and setup instructions complete.
- No dependency on internal Feral File or Bitmark-only modules.