Technical Overview
Deep dive into how SavingsWallet works under the hood
Contents
System Architecture
SavingsWallet is a serverless Next.js application deployed on Vercel that provides automated crypto-to-USDT conversion across two blockchains: Solana and Base. The architecture follows an event-driven pattern for Solana and a polling-based pattern for Base, each optimized for the constraints of their respective environments.
High-Level Data Flow
- 1. User creates a wallet (encrypted on-chain or via our API)
- 2. User deposits tokens to their wallet address
- 3. Incoming transfer is detected (webhook or poll)
- 4. System checks gas balance, USD value, and min-swap threshold
- 5. Swap is executed via the optimal DEX aggregator for each chain
- 6. Transaction result is recorded in the database
- 7. If value exceeds cold wallet threshold, it is forwarded
Solana Swap Monitor (Helius Webhook)
On Solana, incoming transfers are detected via Helius webhooks. Helius provides real-time streaming of on-chain transactions through a webhook callback. When a transaction involving a monitored wallet is confirmed, Helius sends a POST request to /api/webhook/helius with the parsed transaction data.
Webhook Processing Flow
1. Validate HMAC signature (authenticity check)
2. Extract account addresses & parse token transfers
3. Check rate limit (per-wallet, 30s cooldown)
4. Look up wallet in DB by `publicKey`
5. Verify `auto_convert_enabled` flag
6. Check SOL gas balance (min 0.003 SOL)
7. Estimate USD value via Jupiter quote
8. Skip if below $3 minimum swap threshold
9. Execute swap via Jupiter Aggregator API
10. Save transaction record to Supabase
11. If value ≥ cold wallet threshold, forward tokens
Key Details
- • Webhooks are registered per-wallet via the Helius API during wallet activation
- • The HMAC secret is stored as
HELIUS_WEBHOOK_SECRETenv var - • Jupiter API handles best-route discovery across all Solana DEXs
- • Slippage is configurable per-wallet (default 0.5%)
- • Native SOL transfers are not swapped (only SPL tokens)
Base Swap Monitor (Polling + Cron)
Base is an EVM-compatible L2, so it uses a different monitoring approach. Since Helius only supports Solana, Base monitoring is handled via a polling endpoint triggered by a Vercel Cron Job at /api/base/monitor (once daily).
Polling Cycle
1. Fetch all Base wallets with `auto_convert_enabled=true`
2. For each wallet, scan last 200 blocks for ERC20 Transfer events
3. Filter events where `to` address matches the wallet
4. Deduplicate by checking `incoming_tx_hash` in transactions table
5. Fetch token metadata (symbol, decimals) via chain
6. If token is USDT — record directly (no swap needed)
7. If other token — check ETH gas balance (min 0.0005 ETH)
8. Estimate USD value via Aerodrome quote
9. Skip if below $3 minimum swap threshold
10. Execute swap via Aerodrome (Base's leading DEX)
Why Polling vs Webhook?
- • Helius does not support EVM chains — only Solana
- • Vercel Cron Jobs can invoke serverless functions on a schedule
- • Base block times (~2s) mean 200 blocks covers ~7 minutes of history
- • Saves duplicate transactions by checking `incoming_tx_hash`
- • Each wallet's private key is decrypted server-side only during processing
Swap Execution
Swaps are executed through chain-optimized DEX aggregators using the existing liquidity on each network:
Solana → Jupiter
- • Best-route across all Solana DEXs
- • Handles token decimals automatically
- • Configurable slippage
- • Full transaction building & signing
- • Post-swap USDT balance verification
Base → Aerodrome
- • Base's leading liquidity DEX
- • ERC20 approve + swap transaction pair
- • Supports most traded Base tokens
- • ethers v6 for all EVM interactions
- • Quote-before-swap pattern for accuracy
Both swap modules share a common interface: get a quote first, validate the output against the minimum threshold, then execute. Failed swaps are recorded with the error details and the incoming token remains in the wallet for manual recovery.
Security Model
Key Encryption
Private keys are encrypted with AES-256-GCM before being stored in the database. The encryption key is derived from the user's password, which never leaves the browser in plaintext. The server stores only the encrypted blob. We cannot access user funds.
Authentication
API routes that handle sensitive operations (swap, export, create) require the user's password to be sent in the request body. The password is hashed with SHA-256 before being used as the encryption key for AES-256-GCM. This ensures that even if the database is compromised, private keys remain encrypted.
Webhook Verification
Helius webhook requests include an HMAC-SHA256 signature in the x-helius-signature header, verified against a shared secret. This prevents unauthorized actors from injecting fake transactions.
Rate Limiting
In-memory rate limiting prevents duplicate processing within 30-second windows. The system also checks for existing transaction records by `incoming_tx_hash` to ensure idempotency across serverless invocations.
Infrastructure & Data Model
Tech Stack
Next.js 15
App framework
Vercel
Hosting & Cron
Supabase
Postgres DB
Helius
Solana RPC + Webhooks
Jupiter
Solana DEX aggregator
Aerodrome
Base DEX
ethers v6
EVM interactions
Tailwind CSS v4
UI styling
Core Database Tables
wallets
Stores encrypted private keys, public addresses, chain type, auto-convert settings, cold wallet config, and swap preferences per wallet.
transactions
Records every detected incoming transfer and its corresponding swap result. Includes chain, token, amounts, USD values, swap hash, and status.
payments
Tracks USDT accumulations. Each incoming USDT transfer (whether direct or resulting from a swap) is recorded as a payment entry for accounting.
Environment Variables
| Variable | Purpose |
|---|---|
| SUPABASE_URL | Supabase project URL |
| SUPABASE_SERVICE_ROLE_KEY | Server-side DB access |
| SOLANA_RPC_URL | Solana RPC endpoint |
| BASE_RPC_URL | Base L2 RPC endpoint |
| HELIUS_API_KEY | Helius API access |
| HELIUS_WEBHOOK_SECRET | Webhook HMAC verification |
| ENCRYPTION_KEY | Server-side encryption salt |
| JUPITER_API_BASE | Jupiter API base URL |
Thresholds & Configuration
Swap Thresholds
- • Minimum swap: $3 USD equivalent
- • Cold wallet: $500+ → auto-forward
- • Sub-threshold amounts accumulate in wallet
- • Native gas tokens (SOL/ETH) not swapped
Gas Requirements
- • Solana: min 0.003 SOL
- • Base: min 0.0005 ETH
- • Insufficient gas → skip swap, record pending
- • Gas costs are borne by the wallet owner
Rate Limiting
- • Per-wallet cooldown: 30 seconds between swaps
- • Deduplication: by incoming_tx_hash in DB
- • In-memory: resets per serverless invocation
Technical FAQs
What happens if a swap fails?▼
How are private keys stored?▼
Which tokens are supported?▼
How often does the Base monitor run?▼
What is the minimum swap amount?▼
Can I use my own RPC endpoint?▼
Last updated: June 1, 2026 · SavingsWallet is experimental software. Terms