Arc Network Testnet · Chain ID 5042002

The Token Swap DApp
for Arc Network

A full-stack decentralised application for swapping USDC, EURC, and cirBTC on Arc Network Testnet — powered by Circle's App Kit SDK, with on-chain fee collection and real-time analytics.

Arc Testnet · RPC: rpc.testnet.arc.network · Explorer: testnet.arcscan.app

Everything you need to swap on Arc

Arc Swap is a production-grade DApp with a hardened Express API backend and a React frontend. Every interaction is validated on both ends.

🔄

Token Swaps

Swap USDC, EURC, and cirBTC on Arc Network Testnet via Circle's App Kit SDK. Real-time quotes before every execution.

Live Quotes

Get precise pre-swap estimates with exchange rate, platform fee breakdown, and estimated output before committing any transaction.

📊

Price Impact Warnings

Every quote calculates price impact and displays it colour-coded: green (<1%), amber (1–3%), red (>3%). High-impact swaps show prominent warnings.

⚙️

Slippage Tolerance

Choose from 0.1%, 0.5%, or 1.0% slippage presets or enter a custom value. Settings are applied per-session with a visual badge when changed.

💰

Platform Fee Collection

A 0.3% (30 BPS) platform fee is deducted from every swap. Fees are collected to a secure backend wallet and tracked in a dedicated dashboard.

🗃️

Persistent Swap History

Every executed swap is written to PostgreSQL via Drizzle ORM. History survives server restarts and is available via REST API.

🔗

WalletConnect Support

Connects with MetaMask (injected) out of the box. WalletConnect v2 is supported when a project ID is configured, enabling mobile wallets.

📈

Fee Earnings Dashboard

A real-time dashboard displays cumulative fee totals per token and a chronological log of every fee event, auto-refreshing every 30 seconds.

🛡️

Security Hardened

CORS whitelisting, rate limiting (estimate: 30/min, execute: 5/min, global: 300/15min), input validation, and no silent error fallbacks.

Full-stack monorepo

Arc Swap is organised as a pnpm workspace monorepo. The API server and frontend are independent artifacts sharing a typed contract via code-generated hooks.

API Server
  • Express 5 (TypeScript)
  • Pino structured logging
  • express-rate-limit
  • CORS whitelist
  • esbuild bundle
  • Port 8080 → /api
Frontend
  • React 18 + Vite
  • wagmi v3 + viem v2
  • TanStack Query
  • Tailwind CSS + shadcn/ui
  • Circle App Kit SDK
  • Port 19345 → /
Database
  • PostgreSQL
  • Drizzle ORM
  • drizzle-zod schemas
  • swap_history table
  • fee_earnings table
  • Drizzle Kit migrations
Shared Libs
  • @workspace/db
  • @workspace/api-spec
  • @workspace/api-client-react
  • @workspace/api-zod
  • Orval codegen
  • OpenAPI 3.1 contract
Blockchain
  • Arc Network Testnet
  • Chain ID 5042002
  • Circle App Kit SDK
  • ERC-20 transfers
  • MetaMask (injected)
  • WalletConnect v2
Infrastructure
  • pnpm workspaces
  • Node.js 24
  • TypeScript 5.9
  • Reverse proxy routing
  • Environment secrets
  • Replit deployment

Request Flow

User Wallet
  │  connects via MetaMask / WalletConnect
  ↓
React Frontend (Vite)
  │  wagmi hooks → useEstimateSwap / useExecuteSwap (generated)
  │  1. Fee transfer: user sends 0.3% → fee wallet (ERC-20 approve + transferFrom)
  │  2. Swap call: effectiveAmountIn sent to Circle App Kit
  ↓
Express API  /api/swap/estimate  /api/swap/execute
  │  validates input, checks rate limit, calculates fee
  │  calls Circle App Kit → Arc Testnet RPC
  │  writes SwapHistory + FeeEarning records to Postgres
  ↓
Arc Network Testnet  (Chain ID 5042002)
  └─ transaction confirmed → explorerUrl returned

Supported tokens

All tokens are ERC-20 contracts deployed on Arc Network Testnet. Obtain testnet balances from the Circle faucet or Arc testnet faucet.

USDC
USD Coin · 6 decimals
0x3600000000000000000000000000000000000000
EURC
Euro Coin · 6 decimals
0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a
cirBTC
Circle BTC · 8 decimals
Available via Circle App Kit

Network Details

PropertyValue
Network NameArc Testnet
Chain ID5042002
RPC URLhttps://rpc.testnet.arc.network
Block Explorerhttps://testnet.arcscan.app
Native CurrencyETH (18 decimals)
Fee Wallet0xf4a14B84108885AF2f18843DD18761706e47d5F6

REST Endpoints

All endpoints are prefixed with /api. The spec is defined in OpenAPI 3.1 and client hooks are generated via Orval.

GET /api/healthz Health check

Returns server status. Used by the proxy for health checks.

{ "status": "ok" }
POST /api/swap/estimate Get a swap quote · 30 req/min

Returns a pre-swap quote including platform fee deduction, estimated output, exchange rate, and price impact. Does not execute any transaction.

// Request
{
  "tokenIn":  "USDC",
  "tokenOut": "EURC",
  "amountIn": "10.00"
}

// Response
{
  "tokenIn":           "USDC",
  "tokenOut":          "EURC",
  "amountIn":          "10.00",
  "effectiveAmountIn": "9.97",       // after 0.3% fee
  "estimatedAmountOut":"9.94",
  "exchangeRate":      "0.997000",
  "fee":               "0.000000",   // network gas
  "platformFee":       "0.030000",   // 0.3% of amountIn
  "platformFeeAddress":"0xf4a1...d5F6",
  "priceImpact":       "0.30"        // %
}
POST /api/swap/execute Execute a swap · 5 req/min

Executes the swap using the backend wallet via Circle App Kit. Persists the swap record and fee event to the database.

// Request (same shape as estimate)
{ "tokenIn": "USDC", "tokenOut": "EURC", "amountIn": "10.00" }

// Response
{
  "success":          true,
  "transactionHash":  "0xabc123...",
  "explorerUrl":      "https://testnet.arcscan.app/tx/0xabc123...",
  "tokenIn":          "USDC",
  "tokenOut":         "EURC",
  "amountIn":         "9.97",
  "amountOut":        "9.94",
  "timestamp":        "2026-05-14T04:32:00.000Z"
}
GET /api/swap/history Swap history (DB-backed)

Returns the 50 most recent swaps from PostgreSQL, ordered by most recent first.

{ "swaps": [ ...SwapResult ] }
GET /api/wallet/balances Token balances

Returns USDC, EURC, and cirBTC balances for a given address (or the backend wallet if omitted).

GET /api/wallet/balances?address=0x1234...

{
  "address":  "0x1234...",
  "balances": [
    { "token": "USDC",   "balance": "7.461800", "symbol": "USDC" },
    { "token": "EURC",   "balance": "0.000000", "symbol": "EURC" },
    { "token": "cirBTC", "balance": "0.000000", "symbol": "cirBTC" }
  ],
  "network": "Arc Testnet"
}
GET /api/fees Platform fee earnings

Returns cumulative fee totals grouped by token and a list of the 20 most recent fee events.

{
  "totals": [
    { "token": "USDC", "totalFee": "0.150000", "eventCount": 5 }
  ],
  "recent": [
    {
      "id": 1,
      "token": "USDC",
      "feeAmount": "0.030000",
      "transactionHash": "0xabc...",
      "swapAmountIn": "10.00",
      "createdAt": "2026-05-14T04:32:00.000Z"
    }
  ]
}
GET /api/config Client configuration

Returns public configuration values consumed by the frontend on startup.

{
  "feeWalletAddress": "0xf4a14B84108885AF2f18843DD18761706e47d5F6",
  "platformFeeBps": 30
}

Rate Limits

EndpointLimitWindow
POST /api/swap/estimate30 requests1 minute
POST /api/swap/execute5 requests1 minute
All endpoints (global)300 requests15 minutes

Platform fee structure

Arc Swap collects a flat 0.3% platform fee on every swap. The fee is deducted from amountIn before the swap is executed, so the displayed output always reflects the post-fee amount.

0.3%
Platform fee (30 BPS)
ERC-20
On-chain transfer
DB
Persisted per swap
30s
Dashboard refresh

Fee flow

amountIn = 100 USDC
platformFee = 100 × 0.003 = 0.30 USDC  → fee wallet
effectiveAmountIn = 99.70 USDC          → Circle App Kit swap
estimatedAmountOut ≈ 99.40 EURC         → user receives

Getting started

The project runs on Node.js 24 in a pnpm workspace. All commands should be run from the repo root.

1

Clone and install

git clone https://github.com/osr21/arc-swap.git
cd arc-swap
pnpm install
2

Configure environment secrets

Create a .env file or set the following secrets in your deployment environment:

DATABASE_URL=postgresql://user:pass@host:5432/dbname
CIRCLE_KIT_KEY=your_circle_app_kit_key
WALLET_PRIVATE_KEY=0xYOUR_BACKEND_WALLET_PRIVATE_KEY
SESSION_SECRET=random_32_char_string

# Optional — enables WalletConnect in the frontend
VITE_WALLETCONNECT_PROJECT_ID=your_project_id

Get a Circle App Kit key at console.circle.com. Get a free WalletConnect Project ID at cloud.walletconnect.com.

3

Push the database schema

pnpm --filter @workspace/db run push

This creates the swap_history and fee_earnings tables using Drizzle Kit.

4

Run in development

# API server (port 8080)
pnpm --filter @workspace/api-server run dev

# Frontend (port 19345)
pnpm --filter @workspace/arc-swap run dev
5

Add Arc Testnet to MetaMask

The DApp will prompt you to add the network automatically, or add it manually:

Network NameArc Testnet
Chain ID5042002
RPC URLhttps://rpc.testnet.arc.network
Explorerhttps://testnet.arcscan.app
Currency SymbolETH
6

Useful development commands

# Full typecheck (libs + all packages)
pnpm run typecheck

# Regenerate API hooks from OpenAPI spec
pnpm --filter @workspace/api-spec run codegen

# Build API server
pnpm --filter @workspace/api-server run build

# Schema changes → push to DB
pnpm --filter @workspace/db run push

Security model

Arc Swap implements multiple layers of protection on both the client and server. No secrets are ever sent to the frontend.

CORS Whitelist

Only requests from configured Replit domains (and localhost in dev) are accepted. All other origins are rejected.

Rate Limiting

Three tiers: estimate (30/min), execute (5/min), global (300/15min) — preventing abuse and front-running.

Input Validation

Token symbols are validated against an allowlist. Amounts are checked for range (0.01–1,000,000) and numeric validity server-side.

Private Key Isolation

The backend wallet private key is stored as an environment secret and normalised at runtime. It is never logged or returned to clients.

Structured Logging

Pino logger (never console.log) with request/response serialisers that strip sensitive fields before writing to stdout.

Trust Proxy

Express trust proxy is enabled so rate limiting correctly identifies clients behind Replit's reverse proxy.

Zod Schema Validation

API responses are validated against auto-generated Zod schemas before being returned, catching contract drift at runtime.

Explicit Errors

No silent fallbacks. Every failure surface is explicit — from invalid tokens to swap execution failures — with structured error responses.