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_transfers — id (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_events — id, 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
Summary
Six Arc infrastructure tools have been built and integrated into the
arc-relay-bridgeReplit 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
blockNumber + logIndex— Arc has no reorgs, so block number is a stable ordering keyREST API endpoints
/api/indexer/transfersfrom,to,type(NATIVE_SEND/MINT/BURN),txHash/api/indexer/statsDatabase schema
Table:
usdc_transfers—id(txHash-logIndex),blockNumber,blockTime,txHash,logIndex,fromAddress,toAddress,amountNative(18-decimal string),amountUsdc(6-decimal numeric),transferType,isNativeLogTool B — Transaction Memo Indexer
Status: Live, co-located with Tool A worker.
What it does
Indexes
Memoevents 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
/api/indexer/memossender,target,memoId,txHashDatabase schema
Table:
memo_events—id,blockNumber,blockTime,txHash,sender,target,callDataHash,memoId,memoData(hex),memoText(decoded UTF-8 or null),memoIndexTool 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 MessageTransmitter0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275). 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
/api/indexer/cctp/burnsdepositor,destDomain,status(PENDING/COMPLETE/STUCK)/api/indexer/cctp/mintsrecipient,remoteDomainDatabase schemas
cctp_burns:id,blockNumber,blockTime,txHash,sourceDomain,destinationDomain,burnToken,amount,depositor,mintRecipient,nonce,destinationCaller,attestationStatus,mintEventIdcctp_mints:id,blockNumber,blockTime,txHash,destinationDomain,remoteDomain,mintRecipient,amount,mintToken,nonce,burnEventIdTool 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
//transfers/memos/bridgeTechnical notes
/api/indexer/*REST endpoints via Orval-generated React Query hooks0x1234…5678, copyable on clickhttps://testnet.arcscan.app/tx/{hash}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
Deployment
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
evmVersion: paris0x60c0) silently reverts — useconstantinsteadnonReentrantonvalidatePaymasterUserOp— violates ERC-7562, Pimlico rejectsdepositForBurnselector — must use V2 7-param versiononlyEntryPointguard on paymaster functionsUsage
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
Usage (when APS is live)
Infrastructure changes
Database tables added (via Drizzle ORM + PostgreSQL)
usdc_transfers— USDC native transfer eventsmemo_events— On-chain memo eventscctp_burns— CCTP V2 DepositForBurn eventscctp_mints— CCTP V2 MessageReceived eventsindexer_state— Single-row progress tracker (last indexed block, running totals)API server changes
app.set("json replacer", ...)) — drizzlemode:"bigint"columns serialize as strings/api/indexer/*routes (60 req/min, 10 req/min for heavy queries)Arc Testnet gotchas discovered during development
drizzle-kit pushcrashes withCannot serialize BigIntwhen schema has.default(0n)— fix: usemode:"number"with.default(0)for counter columnsblockNumbernottimestampas the ordering key for indexers0xffff…fffe) fires two logs per ERC-20 Transfer (native + ERC-20 mirror) — index only native logs to avoid double-counting