Full-stack infrastructure for an Account Abstraction wallet:
- Backend API: Fastify + Drizzle + PostgreSQL + Redis + ERC-4337 services
- Frontend app: Next.js + Zustand + Tailwind + Web3Auth MPC
- Shared runtime: multi-chain (Ethereum, Polygon, Base, Arbitrum), price feeds, WebSocket updates
| Path | Purpose |
|---|---|
.github/workflows/ci.yml |
CI pipeline (lint, backend tests, frontend build, docker build) |
Backend/ |
Fastify API, database layer, AA services, integration tests |
Frontend/ |
Next.js app, auth + wallet stores, transaction UX, design system |
docker-compose.yml |
Local orchestration for PostgreSQL, Redis, backend, frontend |
Detailed folder docs:
Backend/README.mdBackend/src/README.mdFrontend/README.mdFrontend/app/README.mdFrontend/components/README.mdFrontend/hooks/README.mdFrontend/lib/README.md.github/workflows/README.mdDocs/ARCHITECTURE.md
- Frontend login screen calls
POST /api/v1/auth/send-otp. - User submits OTP to
POST /api/v1/auth/verify. - Backend validates OTP or provider token (Google/Apple), upserts user, returns JWT.
- Frontend stores JWT and initializes MPC session via
web3auth-mpc.ts. - If no wallet exists, frontend auto-creates one for the active chain.
- Frontend calls
GET /api/v1/walletsandGET /api/v1/balances. - Backend resolves wallet rows from PostgreSQL.
- Native balances are fetched from chain RPC clients (
viem). - Fiat conversion is fetched from CoinGecko and cached in Redis/memory.
- Frontend send modal validates recipient/amount and calls
POST /api/v1/transactions/estimate-gas. - On submit, frontend creates a
SmartAccountClientviapermissionless.js+ Web3Auth MPC signer. - UserOperation is signed client-side using MPC (private key never leaves the browser).
- Frontend submits the signed UserOp to Pimlico bundler and logs the result via
POST /api/v1/transactions/log. - Backend persists the transaction record and triggers any configured webhooks.
- Frontend connects to
/wswith JWT. - Backend enforces WebSocket auth timeout and per-IP rate limiting.
- Client subscribes to
prices; backend pushes initial + periodic snapshots.
POST /api/v1/auth/send-otp— Send email OTPPOST /api/v1/auth/verify— Verify OTP / Google / Apple tokenPOST /api/v1/auth/refresh— Rotate refresh token (httpOnly cookie)GET /api/v1/auth/profile— Get authenticated user profilePUT /api/v1/auth/preferences— Update display currency (USD/INR)POST /api/v1/auth/logout— Logout + blacklist tokens
POST /api/v1/wallets— Create walletGET /api/v1/wallets— List user walletsGET /api/v1/wallets/:id— Get wallet by IDGET /api/v1/wallets/:id/balance— Get wallet balanceGET /api/v1/balances— Get all balances
GET /api/v1/wallets/:walletId/transactions— Transaction historyGET /api/v1/transactions/recent— Recent transactionsGET /api/v1/transactions/:hash— Transaction by hashPOST /api/v1/transactions/estimate-gas— Gas estimationPOST /api/v1/transactions/log— Log a frontend-signed transactionPOST /api/v1/transactions/send— Legacy send (disabled, use frontend signing)
POST /api/v1/resolve-ens— Resolve ENS name to address (cached)
POST /api/v1/api-keys— Create API keyGET /api/v1/api-keys— List API keysDELETE /api/v1/api-keys/:id— Revoke API key
GET /api/v1/prices— Get prices for a tokenGET /api/v1/prices/all— Get all supported pricesGET /api/v1/prices/gas— Get gas priceGET /api/v1/chains— List supported chains
GET /ws— Real-time price feed (JWT auth required)
GET /api/docs— Swagger/OpenAPI interactive documentation
Core tables in Backend/src/db/schema.ts:
userswalletstransactionstokensbalancesapi_keys
Relations:
- user -> many wallets
- wallet -> many transactions
- wallet -> many balances
- balance -> token
- Node.js 20+
- npm (backend) and pnpm (frontend)
- Docker (for PostgreSQL and Redis)
docker-compose up -d postgres rediscd Backend
npm install
npm run db:migrate
npm run devcd Frontend
pnpm install
pnpm devApp URLs:
- Frontend:
http://localhost:3000 - Backend:
http://localhost:4000 - Health check:
http://localhost:4000/health
Use examples:
Backend/.env.exampleFrontend/.env.example
Key runtime settings:
- Backend requires
JWT_SECRET. - Backend expects
DATABASE_URLunlessUSE_MOCK_DB=true. - AA flow needs
PIMLICO_API_KEYfor bundler/paymaster calls. - Frontend requires
NEXT_PUBLIC_API_URLandNEXT_PUBLIC_WEB3AUTH_CLIENT_ID.
- Unit/integration tests:
cd Backend && npm test - Coverage:
cd Backend && npm run test:coverage
- Typecheck/build validation:
cd Frontend && pnpm typecheck && pnpm build
ci.yml runs:
- Lint/typecheck both apps
- Backend tests with PostgreSQL + Redis services
- Frontend build
- Optional docker publish on push to
main/master
See DEPLOYMENT.md for comprehensive setup, deployment, and operations documentation including:
- Local development setup
- Docker Compose deployment
- Cloud deployment guides (AWS, Railway, Render, Fly.io, Vercel)
- Third-party service configuration
- Security hardening checklist
- Troubleshooting guide
- Transaction signing is handled entirely on the frontend (MPC + permissionless.js). The backend is a data/config layer.
- Auth tokens use short-lived JWTs (15min) with httpOnly cookie refresh tokens (7 days) and rotation.
- ENS resolution is implemented with Redis caching.
- Currency toggle (USD/INR) is wired to the Zustand store and reflected across the UI.
- Swap feature is marked as "In Development" with a placeholder page.
MIT