Wallet Service is the first component of the Crypto Service V1 microservices refactor. It handles wallet creation, balance queries, address validation, and fee estimation for Solana and BSC (Binance Smart Chain) blockchains.
┌─────────────┐
│ Client │
└──────┬──────┘
│ HTTP/REST
▼
┌─────────────────────────────────────────┐
│ Wallet Service (Go) │
├─────────────────────────────────────────┤
│ ├─ Config Layer (env + defaults) │
│ ├─ Handlers (HTTP endpoints) │
│ ├─ Service Layer (business logic) │
│ ├─ Repository (database operations) │
│ └─ Crypto Manager (Node.js subprocess) │
│ └─ Wallet creation (BIP39/ED25519) │
│ └─ Address validation │
│ └─ Fee estimation │
└────────┬─────────────────────────────────┘
│ PostgreSQL
▼
┌─────────┐
│ DB │
└─────────┘
The service uses a pragmatic hybrid approach:
-
Node.js: Wallet creation (proven, tested, minimal risk)
- Uses
bip39for mnemonic generation - Uses Solana/BSC SDKs for key generation
- Exports as subprocess with JSON output
- Uses
-
Go: Everything else (performance, type safety, integration)
- Encrypts sensitive data (private keys, mnemonics)
- Manages database operations
- Handles HTTP requests
- Coordinates all services
Why this works:
// wallet-service/internal/crypto/manager.go
cmd := exec.Command("node", wm.walletCreatorPath, blockchain)
output, _ := cmd.Output() // Get JSON from Node.js
json.Unmarshal(output, &result) // Parse in Go
encrypted := wm.Encrypt(result.PrivateKey) // Secure in Go
// Store encrypted data in databasewallet-service/
├── config/
├── controllers/
├── middleware/
├── models/
├── routes/
├── utils/
├── Dockerfile
├── docker-compose.yml
├── README.md
POST /wallets/create
Create a new wallet for a user on specified blockchain.
Request:
{
"user_id": "user123",
"blockchain": "solana"
}Response (201 Created):
{
"success": true,
"wallet": {
"id": "uuid-here",
"user_id": "user123",
"blockchain": "solana",
"address": "...",
"public_key": "...",
"is_active": true,
"created_at": 1698000000,
"updated_at": 1698000000
},
"message": "Wallet created successfully"
}Error (400 Bad Request):
{
"success": false,
"error": "wallet already exists for this blockchain"
}GET /wallets/{user_id}
Fetch all wallets for a user.
Query Parameters:
blockchain(optional): Filter by blockchain ("solana" or "bsc")
Response:
{
"success": true,
"wallets": [
{
"id": "uuid1",
"user_id": "user123",
"blockchain": "solana",
"address": "...",
"public_key": "...",
"is_active": true,
"created_at": 1698000000,
"updated_at": 1698000000
},
{
"id": "uuid2",
"user_id": "user123",
"blockchain": "bsc",
"address": "...",
"is_active": true,
"created_at": 1698001000,
"updated_at": 1698001000
}
]
}GET /balance/{user_id}/{currency}
Fetch current balance for a user/currency pair.
Response:
{
"user_id": "user123",
"currency": "SOL",
"balance": 1.5,
"reserved": 0.1,
"available": 1.4,
"updated_at": 1698000000
}GET /balance/{user_id}/history?limit=100
Fetch balance change history.
Response:
{
"user_id": "user123",
"limit": 100,
"count": 5,
"history": [
{
"id": "uuid",
"user_id": "user123",
"currency": "SOL",
"change_amount": 0.5,
"reason": "deposit",
"previous_balance": 1.0,
"new_balance": 1.5,
"created_at": 1698000100
}
]
}POST /validate-address
Validate a blockchain address format.
Request:
{
"address": "DmXDBEYDWJnkA7ZQhEY....",
"blockchain": "solana"
}Response:
{
"valid": true,
"address": "DmXDBEYDWJnkA7ZQhEY....",
"blockchain": "solana"
}GET /fees/{blockchain}
Estimate network fees for a blockchain.
Response:
{
"blockchain": "solana",
"gas_price": 0.000005,
"base_gas": 5000,
"total_fee": 0.025,
"currency": "SOL"
}GET /health
Service health status.
Response (200 OK):
{
"status": "healthy",
"service": "wallet-service",
"version": "1.0.0",
"time": 1698000000
}Response (503 Service Unavailable):
{
"status": "unhealthy",
"service": "wallet-service",
"version": "1.0.0",
"time": 0
}Edit .env file to configure the service:
# Server
PORT=8084
ENV=production
LOG_LEVEL=info
# Database
DATABASE_URL=postgres://user:pass@localhost:5432/crypto_v1?sslmode=disable
DATABASE_MAX_OPEN_CONNS=25
DATABASE_MAX_IDLE_CONNS=5
# RPC Endpoints
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
BSC_RPC_URL=https://bsc-dataseed1.binance.org
# Auth
AUTH_SERVICE_URL=http://auth-service:8082
JWT_SECRET=your_secret_key_here
# Node.js Wallet Creator
WALLET_CREATOR_PATH=./scripts/create-wallet.js
# RPC Configuration
RPC_TIMEOUT_SECONDS=30
RPC_RETRIES=3The service requires the following tables in PostgreSQL:
-- Wallets table
CREATE TABLE wallets (
id UUID PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
blockchain VARCHAR(50) NOT NULL,
address VARCHAR(255) NOT NULL,
public_key TEXT NOT NULL,
private_key_encrypted TEXT NOT NULL,
mnemonic_encrypted TEXT NOT NULL,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id, blockchain)
);
-- Wallet balances table
CREATE TABLE wallet_balances (
id UUID PRIMARY KEY,
wallet_id UUID REFERENCES wallets(id),
user_id VARCHAR(255) NOT NULL,
currency VARCHAR(20) NOT NULL,
balance DECIMAL(18, 8) DEFAULT 0,
reserved DECIMAL(18, 8) DEFAULT 0,
available DECIMAL(18, 8) DEFAULT 0,
last_updated TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id, currency)
);
-- Balance history (audit trail)
CREATE TABLE balance_history (
id UUID PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
currency VARCHAR(20) NOT NULL,
change_amount DECIMAL(18, 8) NOT NULL,
reason VARCHAR(100) NOT NULL,
previous_balance DECIMAL(18, 8),
new_balance DECIMAL(18, 8),
created_at TIMESTAMP DEFAULT NOW()
);
-- Create indexes
CREATE INDEX idx_wallets_user_id ON wallets(user_id);
CREATE INDEX idx_wallets_address ON wallets(address, blockchain);
CREATE INDEX idx_balance_user_id ON wallet_balances(user_id);
CREATE INDEX idx_balance_history_user_id ON balance_history(user_id);- MYSQL 10+
- Node.js 16+ (for wallet creation script)
-
Set up environment:
cp .env.example .env # Edit .env with your configuration -
Create database:
createdb crypto_v1 mysql crypto_v1 < schema.sql -
Run the service:
go run ./cmd/main.go
Service starts on
http://localhost:8084 -
Test the service:
# Create a wallet curl -X POST http://localhost:8084/wallets/create \ -H "Content-Type: application/json" \ -d '{"user_id":"user123","blockchain":"solana"}' # Check health curl http://localhost:8084/health
-
Build image:
docker build -t wallet-service:1.0.0 . -
Run with docker-compose:
docker-compose up -d
-
Check logs:
docker logs wallet-service
The service is designed to integrate with the auth-middleware package. Add authentication middleware:
router.Use(authMiddleware.AuthRequired("crypto:wallet:read"))The Indexer Service will fetch wallet addresses via:
GET /wallets/{user_id}
The Payment Processor will call:
GET /balance/{user_id}/{currency}
POST /validate-address
The VTU Service can query balances:
GET /balance/{user_id}/SOL
GET /balance/{user_id}/BNB
| Operation | Typical Latency | Notes |
|---|---|---|
| Create Wallet | 2-5s | Calls Node.js subprocess |
| Get Wallets | <100ms | Database query |
| Get Balance | <50ms | Database query |
| Validate Address | <10ms | Local computation |
| Estimate Fees | <20ms | Local computation |
-
Encryption at Rest:
- Private keys encrypted with AES-256-GCM
- Mnemonics encrypted with AES-256-GCM
- Encryption key derived from JWT secret
-
No Private Keys in Response:
- API never returns private keys or mnemonics
- Encrypted versions stored in database
-
Database Access Control:
- All database connections use prepared statements
- SQL injection impossible
-
Wallet Isolation:
- Each user has separate wallet per blockchain
- Unique constraint prevents duplicates
Curl GET -x http://localhost:8084/health- Request latency (p50, p95, p99)
- Error rate (% failed requests)
- Database connection pool utilization
- Wallet creation success rate
- RPC call failures
curl http://localhost:8084/healthtail -f logs/wallet-service.log- Database backups configured
- Connection pool tuning optimized for load
- Error logging and monitoring in place
- Rate limiting configured
- SSL/TLS certificates installed
- Health checks integrated with load balancer
- Graceful shutdown tested
version: '3.8'
services:
db:
image: mariadb:10.4
container_name: wallet-db
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_ROOT_PASSWORD: ""
MYSQL_DATABASE: wayadata_walletDB
MYSQL_USER: root
MYSQL_PASSWORD: ""
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
ports:
- "3306:3306"
volumes:
- ./schema.sql:/docker-entrypoint-initdb.d/schema.sql
networks:
- walletnet
wallet-service:
build: .
container_name: wallet-service
ports:
- "8084:8084"
environment:
DB_NAME: "wayadata_walletDB"
DB_USER: "root"
DB_PASSWORD: ""
DB_HOST: "db"
DB_PORT: "3306"
JWT_SECRET: ""
WALLET_CREATOR_PATH: "./scripts/create-wallet.js"
depends_on:
db:
condition: service_healthy
networks:
- walletnet
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: wallet-phpmyadmin
environment:
PMA_HOST: db
PMA_USER: root
PMA_PASSWORD: ""
ports:
- "8081:80" # <-- FIXED
depends_on:
db:
condition: service_healthy
networks:
- walletnet
networks:
walletnet:
driver: bridge
Error: failed to ping database
- Check
DATABASE_URLin.env - Ensure PostgreSQL is running
- Verify network connectivity
Error: wallet creation timeout
- Check Node.js is installed:
node --version - Verify
WALLET_CREATOR_PATHexists - Check Node.js subprocess logs
- Ensure blockchain parameter is "solana" or "bsc"
- Check address format (Solana: 44 chars base58, BSC: 42 chars hex)
-
Auth Middleware Integration:
- Add scope-based access control
- Validate tokens from auth service
-
Dynamic Fee Estimation:
- Call RPC endpoints for real-time gas prices
- Cache results with TTL
-
WebSocket Support:
- Real-time balance updates
- Subscribe to wallet events
-
Multi-signature Wallets:
- Support for threshold signatures
- Distributed key management
-
Rate Limiting:
- Per-user request limits
- Sliding window algorithm
- Indexer Service: Detects deposits, publishes events
- Payment Processor: Consumes deposit events, updates balances
- Auth Service: Provides token validation
- VTU Service: Queries balances for purchases
For issues or questions, contact the dev team or create an issue in the repository.