Skip to content

Arc Infrastructure Tools — Documentation Report (July 2026) #7

Description

@osr21

Summary

Six Arc infrastructure tools have been built and integrated into the arc-relay-bridge Replit project since the last documented commit (2026-06-03). This issue serves as the canonical documentation reference for all new components.


Tool A — USDC Transfer Indexer + REST API

Status: Live, polling Arc Testnet every 2 seconds.

What it does

A background worker running inside the API server indexes all native USDC transfer events on Arc Testnet in real time. It listens to EIP-7708 logs emitted by the native USDC emitter (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE) — the single authoritative source for USDC balance changes on Arc.

Key decisions

  • Indexes only native emitter logs (not the ERC-20 mirror) to avoid double-counting
  • Orders by blockNumber + logIndex — Arc has no reorgs, so block number is a stable ordering key
  • On startup: reads last indexed block from DB and resumes; caps catch-up at 500 blocks on first run
  • Polls every 2s (~4 Arc blocks per cycle given ~0.48s block time)

REST API endpoints

Method Path Description
GET /api/indexer/transfers Paginated USDC transfer list. Filters: from, to, type (NATIVE_SEND/MINT/BURN), txHash
GET /api/indexer/stats Aggregate stats: last indexed block, totals, CCTP domain breakdown

Database schema

Table: usdc_transfersid (txHash-logIndex), blockNumber, blockTime, txHash, logIndex, fromAddress, toAddress, amountNative (18-decimal string), amountUsdc (6-decimal numeric), transferType, isNativeLog


Tool B — Transaction Memo Indexer

Status: Live, co-located with Tool A worker.

What it does

Indexes Memo events from Arc's on-chain memo contract (0x5294E9927c3306DcBaDb03fe70b92e01cCede505). Each memo event carries a sender, target, callDataHash, memoId, and raw memo bytes. The indexer attempts UTF-8 decoding of the memo payload and stores the human-readable text if valid.

REST API endpoint

Method Path Description
GET /api/indexer/memos Paginated memo list. Filters: sender, target, memoId, txHash

Database schema

Table: memo_eventsid, blockNumber, blockTime, txHash, sender, target, callDataHash, memoId, memoData (hex), memoText (decoded UTF-8 or null), memoIndex


Tool E — CCTP Bridge Analytics (Indexer component)

Status: Live, co-located with Tools A + B.

What it does

Same worker also indexes CCTP V2 burn events (from TokenMessenger 0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA) and mint events (from MessageTransmitter 0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275). Burns track attestation status (PENDING → COMPLETE). When a mint is observed and its source domain matches Arc, the corresponding burn row is updated to COMPLETE via a transactional join.

REST API endpoints

Method Path Description
GET /api/indexer/cctp/burns CCTP burn events. Filters: depositor, destDomain, status (PENDING/COMPLETE/STUCK)
GET /api/indexer/cctp/mints CCTP mint events. Filters: recipient, remoteDomain

Database schemas

  • cctp_burns: id, blockNumber, blockTime, txHash, sourceDomain, destinationDomain, burnToken, amount, depositor, mintRecipient, nonce, destinationCaller, attestationStatus, mintEventId
  • cctp_mints: id, blockNumber, blockTime, txHash, destinationDomain, remoteDomain, mintRecipient, amount, mintToken, nonce, burnEventId

Tool E — Arc Analytics Dashboard (Frontend)

Status: Live at /arc-analytics/.

What it does

A real-time dark-themed analytics dashboard for Arc Testnet built with React 19 + Vite + Recharts + shadcn/ui.

Pages

Route Purpose
/ Overview — indexer state (last block, totals), CCTP domain breakdown bar charts, auto-refreshes every 10s
/transfers USDC Transfer Explorer — searchable/filterable table with pagination
/memos Memo Event Explorer — decoded memo text, raw hex tooltip
/bridge CCTP Bridge Activity — Burns tab (with attestation status badges) + Mints tab

Technical notes

  • All data comes from the /api/indexer/* REST endpoints via Orval-generated React Query hooks
  • Address display: truncated 0x1234…5678, copyable on click
  • Transaction links: https://testnet.arcscan.app/tx/{hash}
  • Amount display: always shows 6-decimal USDC value (never raw 18-decimal native wei)

Tool C — The Graph Subgraph

Status: Ready to deploy. Files at scripts/src/graph/.

What it does

A Graph Protocol subgraph that indexes the same Arc Testnet events via TheGraph's decentralized infrastructure (alternative/complement to the centralized indexer above).

Files

scripts/src/graph/
  schema.graphql          — UsdcTransfer, MemoEvent, CctpBurn, CctpMint entity types
  subgraph.yaml           — data sources: NativeUsdcEmitter, MemoContract, TokenMessenger, MessageTransmitter
  src/
    usdc.ts               — AssemblyScript mapping for Transfer events
    memo.ts               — AssemblyScript mapping for Memo events
    cctp.ts               — AssemblyScript mapping for DepositForBurn + MessageReceived
  abis/
    ERC20.json, Memo.json, TokenMessenger.json, MessageTransmitter.json
  package.json

Deployment

cd scripts/src/graph
npm install
graph auth --studio <deploy-key>
graph codegen && graph build
graph deploy --studio arc-relay-bridge

Tool D — Contract Compatibility Linter

Status: Usable. Script at scripts/src/lint-arc-contract.ts.

What it does

A CLI linter that detects Arc Testnet compatibility issues in Solidity contracts before deployment. Fetches on-chain bytecode and runs 9 static checks.

Checks

Code Check
ARC-001 PUSH0 opcode detected — contract requires evmVersion: paris
ARC-002 2-immutable constructor init pattern (0x60c0) silently reverts — use constant instead
ARC-003 nonReentrant on validatePaymasterUserOp — violates ERC-7562, Pimlico rejects
ARC-004 V1 CCTP 4-param depositForBurn selector — must use V2 7-param version
ARC-005 Missing EntryPoint onlyEntryPoint guard on paymaster functions
ARC-006 Constructor arity mismatch for known paymaster pattern
ARC-007 Stale gas price usage — requires ≥30% premium on Arc
ARC-008 eth_estimateGas reliance for complex calls — use hardcoded gas limits
ARC-009 wallet_switchEthereumChain race condition pattern

Usage

pnpm --filter @workspace/scripts run lint-contract <contract-address>
# Example:
pnpm --filter @workspace/scripts run lint-contract 0xEE39e1690F1bE07e8a68813f57cE3142197CECf6

Tool G — APS (Arc Privacy Sector) SDK

Status: Typed stubs ready for integration. Package at lib/arc-privacy-sdk/.

What it does

A TypeScript SDK providing typed interfaces and client stubs for the Arc Privacy Sector (APS) — a pre-launch privacy infrastructure layer on Arc. Built ahead of APS mainnet deployment to enable downstream integration.

Package

@workspace/arc-privacy-sdk
  src/types.ts     — PrivacyNote, NoteCommitment, ShieldedBalance, PrivacyProof types
  src/client.ts    — ArcPrivacyClient (APS RPC + shield/unshield/transfer operations)
  src/encrypt.ts   — AES-256-GCM note encryption utilities
  src/index.ts     — barrel export

Usage (when APS is live)

import { ArcPrivacyClient } from "@workspace/arc-privacy-sdk";
const aps = new ArcPrivacyClient({ rpcUrl: "https://rpc.testnet.arc.network", chainId: 5042002 });
const note = await aps.shield(signer, usdcAmount);

Infrastructure changes

Database tables added (via Drizzle ORM + PostgreSQL)

  • usdc_transfers — USDC native transfer events
  • memo_events — On-chain memo events
  • cctp_burns — CCTP V2 DepositForBurn events
  • cctp_mints — CCTP V2 MessageReceived events
  • indexer_state — Single-row progress tracker (last indexed block, running totals)

API server changes

  • BigInt JSON serializer added globally (app.set("json replacer", ...)) — drizzle mode:"bigint" columns serialize as strings
  • Rate limiter added for /api/indexer/* routes (60 req/min, 10 req/min for heavy queries)
  • OpenAPI spec updated with all 5 indexer endpoints; Orval codegen regenerated

Arc Testnet gotchas discovered during development

  • drizzle-kit push crashes with Cannot serialize BigInt when schema has .default(0n) — fix: use mode:"number" with .default(0) for counter columns
  • Arc block time: ~0.48s. Use blockNumber not timestamp as the ordering key for indexers
  • Arc USDC emitter (0xffff…fffe) fires two logs per ERC-20 Transfer (native + ERC-20 mirror) — index only native logs to avoid double-counting

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions