Skip to content

Proposal: multi-wallet viewer screen + gray/orange brand theme for miner-app #485

@adamtpang

Description

@adamtpang

Proposal: Multi-wallet viewer screen + Quantus brand theme for miner-app

Working prototype is running locally as a watch-only Python web dashboard at localhost:7878 while this proposal is reviewed. It queries the local node's RPC directly for any number of tracked SS58 addresses and renders a gray + orange UI matching the proposed Quantus design direction.

This doc proposes folding the same feature into miner-app/ as a first-class screen, and applying the gray + orange palette across the existing dashboard.


Motivation

Today the miner app has a single MinerBalanceCard tied to the wormhole preimage configured in setup. That's the right primary view for "what am I earning?" — but it leaves three real gaps:

  1. Mining rewards land in the standard Balances pallet, not as wormhole UTXOs (see pallets/mining-rewards/src/lib.rs:220: T::Currency::mint_into(miner, reward)). The current WormholeUtxoService.getUnspentBalance view does not surface them. A miner who has won blocks sees "0 QUAN" in the GUI while System.Account(addr).data.free shows a non-zero balance. Reported live on this account: qzjtdBwdhUVKtJVi2hatJ3H6XCuEmNxkYCKem5k8se64mz3mE → 0.7739 QUAN on chain, 0 in current GUI.
  2. No multi-wallet view. A user with a CLI-generated wallet and a phone wallet has to context-switch between two UIs to reconcile balances.
  3. Default Material 3 theme ships out of the box. The dashboard reads as a generic Flutter app, not as Quantus.

Feature A — Wallet viewer screen (watch-only)

User-facing behaviour

A new route at /wallets reachable from the dashboard's hamburger menu, alongside Logout (Full Reset) and Settings.

  • Auto-imports the active miner's wormhole address with the label "Mining wallet".
  • Adds arbitrary addresses via a + button → modal with an SS58 input field (paste-only; no key material).
  • Shows for each row: label, full SS58 (truncated with copy button), free balance from System.Account(addr).data.free, status pill (Active / No account / Error).
  • Total at the bottom.
  • Auto-refresh every 10 s; mining-event-driven refresh hook reusing the existing MinerConfig.blockSubmittedLogMarker pattern from miner_balance_card.dart.
  • Persists wallet list to local app storage (Hive or shared_preferences — whatever the project's existing convention is).

Why standard System.Account, not wormhole UTXO

Mining rewards mint into the standard Balances pallet at the wormhole address. To make those balances visible to the user without a wormhole withdrawal proof, we need a direct state_getStorage(System.Account(addr)) query. The reference Python prototype shows this works against the local node with no node-side changes.

The wormhole UTXO view stays the right primary view for "spendable, privacy-protected balance" and should not be removed — this is an additive secondary view.

Suggested Dart structure

miner-app/lib/features/wallets/
  wallets_screen.dart                  // ListView of WalletTile
  wallet_tile.dart                     // label, address, balance, status
  add_wallet_dialog.dart               // paste SS58, validate, save
  wallet_repository.dart               // load/save list, in-memory cache
  wallet_balance_service.dart          // state_getStorage queries via RPC
miner-app/lib/main.dart                // add `/wallets` GoRoute

The balance service should reuse the existing quantus_sdk RPC client. Storage-key computation is twox128("System") || twox128("Account") || blake2_128_concat(account_id); the SDK already has these primitives (qp-poseidon-core and friends).

Reference implementation

The Python prototype at scripts/balance-viewer.py in adamtpang/quantus-windows-miner (or wherever this contrib lands) implements the SS58 decode, storage-key derivation, RPC call, and AccountInfo decode in ~50 lines using only xxhash, base58, and hashlib. The HTML dashboard demonstrates the gray + orange aesthetic targeted in Feature B below.

Feature B — Quantus gray + orange theme

The dashboard today inherits ThemeData.dark(useMaterial3: true), which is why buttons read as Material default blue and sliders as Material default purple.

Proposed palette (Flutter constants)

// miner-app/lib/src/theme/quantus_theme.dart
class QuantusColors {
  // Neutral scale (background → foreground)
  static const bg0     = Color(0xFF0C0C0D);
  static const bg1     = Color(0xFF161618);
  static const bg2     = Color(0xFF1F1F23);
  static const bg3     = Color(0xFF2A2A2F);
  static const border  = Color(0x12FFFFFF);   // rgba(255,255,255,0.07)
  static const fg      = Color(0xFFF4F4F5);
  static const fgMuted = Color(0xFFA1A1AA);
  static const fgDim   = Color(0xFF71717A);

  // Quantus orange
  static const orange       = Color(0xFFF97316);
  static const orangeHover  = Color(0xFFFB923C);
  static const orangeSoft   = Color(0x1FF97316); // rgba(249,115,22,0.12)

  // Status
  static const err = Color(0xFFEF4444);
}

ThemeData quantusTheme() => ThemeData(
  useMaterial3: true,
  brightness: Brightness.dark,
  scaffoldBackgroundColor: QuantusColors.bg0,
  colorScheme: const ColorScheme.dark(
    primary: QuantusColors.orange,
    secondary: QuantusColors.orange,
    surface: QuantusColors.bg1,
    error: QuantusColors.err,
  ),
  // ... typography, card theme, button theme matching the HTML prototype
);

Apply in main.dart:

MaterialApp.router(
  title: 'Quantus Miner',
  theme: quantusTheme(),
  routerConfig: _router,
);

What this changes visibly

  • "Start Node" button: blue → orange
  • Sliders (CPU Workers, GPU Devices): purple → orange
  • Idle/Mining pill: maintains shape, picks up orange accent for active states
  • Backgrounds shift from default dark to a tighter, more brand-aligned gray scale
  • Update banner: keeps blue for "info" or shifts to orange for emphasis (design call)

Acceptance criteria

  • /wallets route exists and is reachable from the existing menu
  • First open auto-imports the current mining wallet (read-only — no key access)
  • User can add additional addresses by paste; invalid SS58 strings show inline error
  • Each row shows balance from state_getStorage(System.Account(addr)) and refreshes every 10 s
  • List persists between app launches
  • No new dependencies on the node beyond what quantus_sdk already exposes
  • QuantusColors + quantusTheme() applied app-wide; existing screens visually pass through unchanged in layout
  • Existing balance card on the dashboard remains as the "spendable wormhole balance" primary view

Out of scope (defer to follow-ups)

  • Sending / withdrawing from this screen (read-only intentionally)
  • Wormhole withdrawal proof generation
  • Per-wallet transaction history
  • Theme switching / light mode

Happy to PR

If a maintainer can confirm the route placement and any naming preferences (/wallets vs /balances vs /portfolio), I'm happy to put up a draft PR with the new screen + theme. The Python prototype is a 1:1 reference for the visible behaviour.

Closes the dashboard mystery in adamtpang's stuck-dashboard issue by giving users a working balance view independent of the wormhole-UTXO sync state.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions