feat: add neon color picker for wallet management
- Replace muted Tailwind palette with 16-color neon palette - Add clickable color dot in sidebar that opens a popup swatch grid - Allow color override for all wallets (including embedded) - Fix getColorForWallet to respect localStorage override - Fix duplicate renameWallet in wallets.js - Update Dockerfile to serve ESM modules via nginx
This commit is contained in:
66
AGENTS.md
66
AGENTS.md
@ -10,11 +10,24 @@ docker build -t cbBTC-dashboard . && docker run -p 8080:80 cbBTC-dashboard
|
||||
|
||||
Or just open `index.html` in a browser (without the `/api/` proxy, only the Kraken BTC price chart will work).
|
||||
|
||||
## Architecture
|
||||
|
||||
The codebase is split into three vanilla ESM modules plus the single-page dashboard:
|
||||
|
||||
| Module | Purpose |
|
||||
|---|---|
|
||||
| `wallets.js` | **`WalletManager`** — localStorage state, chain-specific address validation, verification lifecycle |
|
||||
| `verifier.js` | **`WalletVerifier`** — EIP-712 typed-data signing via `window.ethereum`, user rejection handling |
|
||||
| `stream.js` | **`WalletStreamManager`** — single WebSocket with BroadcastChannel leader election, exponential backoff + jitter |
|
||||
|
||||
## File layout
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `index.html` | Everything. Frontend, embedded chart data, inline JS logic. Edit here. |
|
||||
| `index.html` | Dashboard UI. Embedded chart data, ApexCharts, TailwindCSS. Loads modules via `<script type="module">`. |
|
||||
| `wallets.js` | `WalletManager` — anonymous localStorage wallet state, add/remove/verify/revoke |
|
||||
| `verifier.js` | `WalletVerifier` — `window.ethereum` connection + EIP-712 signature flow |
|
||||
| `stream.js` | `WalletStreamManager` — single WS, cross-tab leader election, event routing |
|
||||
| `Dockerfile` | 4 lines. Copies `index.html` and `default.conf` into `nginx:alpine`. |
|
||||
| `default.conf` | Reverse proxy: `/api/` → `http://192.168.1.102:8000/api/`. |
|
||||
| `aave_portfolio.md` / `wallet_portfolio.md` | Reference data dumps. NOT consumed by the app. |
|
||||
@ -34,11 +47,62 @@ Or just open `index.html` in a browser (without the `/api/` proxy, only the Krak
|
||||
- **Tracked wallet:** `0x0c1a4a060e119f981412e323104d1c134d413dba` ("penguin", Base)
|
||||
- **Token decimals:** cbBTC=8, WETH=18, USDC=6
|
||||
|
||||
## Module API
|
||||
|
||||
Each module is loaded via `<script type="module">` in `index.html`:
|
||||
|
||||
```js
|
||||
import { WalletManager } from './wallets.js';
|
||||
import { WalletVerifier } from './verifier.js';
|
||||
import { WalletStreamManager } from './stream.js';
|
||||
|
||||
const wm = new WalletManager();
|
||||
wm.loadWallets();
|
||||
|
||||
const verifier = new WalletVerifier(wm);
|
||||
const stream = new WalletStreamManager(wm);
|
||||
stream.connect();
|
||||
```
|
||||
|
||||
### WalletManager
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `loadWallets()` | Reads from localStorage, sanitizes (always `isVerified: false`) |
|
||||
| `addWallet(address, chain, nickname)` | Validates format, appends, persists |
|
||||
| `removeWallet(address, chain)` | Drops from state, persists |
|
||||
| `verifyWallet(address, chain, signature, messageData)` | Sets `isVerified: true` |
|
||||
| `revokeVerification(address, chain)` | Resets to unverified |
|
||||
| `findWallet(address, chain)` | Lookup helper |
|
||||
| `getWallets()` | Returns deep copy of state |
|
||||
|
||||
### WalletVerifier
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `triggerWalletVerification(chain, nickname)` | Full flow: eth_requestAccounts → EIP-712 sign → add + verify |
|
||||
| `connect()` | Quick connect check (no signature) |
|
||||
|
||||
EIP-712 domain: `{ name: "Anonymous Wallet Tracker", version: "1", chainId: 1 }`
|
||||
|
||||
### WalletStreamManager
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `connect()` | Triggers BroadcastChannel leader election → opens single WS |
|
||||
| `disconnect()` | Closes WS + BC, cancels timers |
|
||||
| `on(event, callback)` | Register callback per event type |
|
||||
| `subscribeToNewWallet(wallet)` | Dynamic subscribe (leader → WS, follower → BC) |
|
||||
| `unsubscribeFromWallet(address, chain)` | Dynamic unsubscribe |
|
||||
|
||||
Cross-tab leader election uses `BroadcastChannel("dione_shared_stream")` with a 200ms timeout. Leader-death broadcast triggers failover election. Reconnect uses exponential backoff (1s → 30s) with ±25% jitter.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `apiBase = window.location.origin` — the dashboard relies on nginx proxy to reach the backend at `192.168.1.102:8000`. Running without Docker/proxy means the Aave table and price charts fail silently.
|
||||
- No linting, no type-checking, no CI. Validate changes by opening the HTML in a browser.
|
||||
- Adding chart data? Update the embedded arrays (`walletCumulData`, etc.) — they are plain JS arrays of `[timestampMs, value]` pairs.
|
||||
- `wallets.js` always forces `isVerified: false` on `loadWallets()` — persisted signatures are discarded. Verification must go through `WalletVerifier`.
|
||||
|
||||
## Coding Guidelines
|
||||
|
||||
|
||||
Reference in New Issue
Block a user