Wallets
Solana keypair management with client-side AES-256-GCM encryption. Keys never leave your browser unencrypted.
Operations
| Operation | Description |
|---|---|
| Create | Generates new Keypair.generate(), encrypts private key, stores in Supabase |
| Import | Paste base58 private key, validates keypair, encrypts and stores |
| Withdraw | Send SOL to any address. MAX button drains full balance minus rent. |
| Export key | Shows private key for 30 seconds then auto-hides |
| Delete | Removes from Supabase + clears key cache. Bulk delete available. |
| Rename | Custom display name, synced to Supabase |
| Reorder | Drag and drop. Order persisted in localStorage (walletOrder) |
| Rotation | Creates new wallet, transfers all SOL from current to new, sets new as active. One TX. |
Encryption
| Parameter | Value |
|---|---|
| Algorithm | AES-256-GCM |
| Key derivation | PBKDF2 with 100,000 iterations, SHA-256 |
| Salt | 16 bytes random per key |
| IV | 12 bytes random per encryption |
| CryptoKey storage | IndexedDB (ql_keystore database, keys store) |
| Session timeout | 24 hours |
| Server stores | encrypted_secret_key + iv (ciphertext only) |
Key cache
- Decrypted keys cached in-memory Map with 5-minute TTL
- Cleared on logout
- Prevents repeated decryption during multi-wallet operations
Balance tracking
- Refresh TTL: 10 seconds per wallet (skips if fetched within TTL)
- Batch refresh:
getMultipleAccountsInfofor all wallets at once - Guard:
refreshInFlightflag prevents concurrent batch calls
Active wallet
One wallet is active at a time (used as dev wallet for launches). Persisted to Supabase settings.active_wallet_id. Anti-bubblemap wallets (names starting with [AM:) are filtered from the main wallet list.