A unified API layer for Safe blockchain data, designed to replace the fan-out pattern where Client Gateway queries 50+ Transaction Services.
- Unified API: Single endpoint for multi-chain Safe data
- Backwards Compatible: REST API matching existing TX Service format
- Type-Safe: tRPC + Zod for end-to-end type safety
- Incremental Adoption: Proxy → Hybrid → Native modes
- Production Ready: Circuit breakers, caching, structured logging
| Technology | Purpose |
|---|---|
| Bun | Fast JS runtime with native TypeScript |
| Hono | Fast, lightweight HTTP framework |
| tRPC | Type-safe RPC |
| Zod | Runtime validation |
| Pino | Structured logging |
| Redis | Caching layer |
# Install dependencies
bun install
# Start Redis (optional, for caching)
docker compose -f docker-compose.dev.yml up -d
# Start development server
bun run dev
# Chain configurations are fetched from Safe Config Service automatically
# Optionally override specific chains with TX_SERVICE_URLS
TX_SERVICE_URLS='{"1":"https://custom-tx-service.example.com"}' bun run dev# Build and run with Docker Compose
docker compose up --build
# Or build image manually
docker build -t safe-transaction-service-api .
docker run -p 3000:3000 safe-transaction-service-api# Health check
curl http://localhost:3000/health
# Get Safe info (requires TX_SERVICE_URLS)
curl http://localhost:3000/api/v1/chains/1/safes/0x0DA0C3e52C977Ed3cBc641fF02DD271c3ED55aFe
# Get Safes by owner
curl http://localhost:3000/api/v1/chains/1/owners/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/safes
# Get balances
curl http://localhost:3000/api/v1/chains/1/safes/0x0DA0C3e52C977Ed3cBc641fF02DD271c3ED55aFe/balances| Endpoint | Description |
|---|---|
GET /health |
Health check |
GET /ready |
Readiness check |
GET /api/v1/chains/:chainId/safes/:address |
Get Safe info |
GET /api/v1/chains/:chainId/owners/:address/safes |
Get Safes by owner |
GET /api/v1/chains/:chainId/safes/:address/balances |
Get Safe balances |
GET /api/v1/chains/:chainId/safes/:address/multisig-transactions |
Get transactions |
GET /api/v1/chains/:chainId/transactions/:safeTxHash |
Get transaction by hash |
// Type-safe client
const safe = await client.safe.get({ chainId: 1, address: '0x...' })
const safes = await client.owner.getSafes({ chainId: 1, ownerAddress: '0x...' })
const balances = await client.balance.get({ chainId: 1, safeAddress: '0x...' })| Variable | Description | Default |
|---|---|---|
NODE_ENV |
Environment | development |
PORT |
Server port | 3000 |
LOG_LEVEL |
Logging level | info |
REDIS_URL |
Redis connection URL | (disabled) |
SAFE_CONFIG_BASE_URI |
Config Service URL for chain configs | https://safe-config.safe.global/ |
USE_TX_SERVICE_VPC_URL |
Use VPC URLs for transaction services | false |
TX_SERVICE_URLS |
(Optional) JSON map override for chainId to URL | {} |
CORS_ORIGINS |
Comma-separated allowed origins | * |
REQUEST_TIMEOUT_MS |
Request timeout | 30000 |
bun run dev # Development server with hot reload
bun run start # Start production server
bun run build # Build for production
bun run test # Run unit + integration tests
bun run test:unit # Run unit tests only
bun run test:integration # Run integration tests only
bun run test:e2e # Run E2E tests (needs network)
bun run test:coverage # Run with coverage
bun run lint # ESLint
bun run lint:fix # ESLint with auto-fix
bun run format # Prettier
bun run typecheck # TypeScript checksrc/
├── config/ # Configuration (env, constants)
├── domains/ # Business domains
│ ├── chain/ # Chain configuration
│ ├── safe/ # Safe info
│ ├── owner/ # Owner's safes
│ ├── transaction/ # Transactions
│ └── balance/ # Token balances
├── providers/ # Data access
│ ├── config/ # Config Service client
│ ├── proxy/ # TX Service client
│ ├── cache/ # Redis client
│ └── data-provider.ts # Abstraction layer
├── infrastructure/ # HTTP, tRPC, middlewares
│ ├── http/ # REST routes
│ ├── trpc/ # tRPC setup
│ ├── middleware/ # Hono middlewares
│ └── health/ # Health endpoints
└── shared/ # Utilities, errors, types
| Document | Description |
|---|---|
| Overview | Documentation structure |
| Phase 1 Requirements | Proxy mode requirements |
| Phase 1 Architecture | Proxy mode architecture |
| Phase 1 Tasks | Implementation checklist |
| Infrastructure Requirements | AWS deployment & circuit breakers |
| CLAUDE.md | Development guidelines |
The service automatically fetches chain configurations from Safe Config Service. This provides:
- Dynamic chain support: No manual configuration needed for new chains
- VPC URL support: Use internal network URLs for better performance (
USE_TX_SERVICE_VPC_URL=true) - Override capability: Use
TX_SERVICE_URLSto override specific chains for testing
- TX_SERVICE_URLS override (if configured)
- Config Service (VPC or public URL based on
USE_TX_SERVICE_VPC_URL) - Error if chain not found
# Use Config Service for all chains (recommended)
SAFE_CONFIG_BASE_URI=https://safe-config.safe.global/
# Use VPC URLs for internal network optimization
USE_TX_SERVICE_VPC_URL=true
# Override specific chains for local testing
TX_SERVICE_URLS='{"1":"http://localhost:8000","137":"https://custom-polygon.example.com"}'Mode 1: PROXY Mode 2: HYBRID Mode 3: NATIVE
───────────── ────────────── ─────────────
Forwards to Reads from unified Full unified
existing TX DB, falls back to database
Services TX Services
Zero migration Gradual migration Final state
MIT