Files
neuron-tai/docs/issues/41-account-wallet-keypair.md
2026-07-06 14:17:36 +03:00

3.0 KiB

US-041 — Account wallet: browser-extension signing, in-browser generation, export-only

Status: planned Priority: Medium (not needed for devnet friends test; needed before mainnet) Stage: Designed

Context

Registration accepts an optional wallet field (a pubkey string) and the dashboard never shows it. Users need a visible wallet address on the account panel and a path to real Solana later, without the tracker ever holding user private keys.

Today wallets matter in two places: client deposit attribution (bind_wallet → deposit watcher) and node payout identity (Pending Balance keyed by wallet). Accounts themselves hold no keypair — and will stay that way.

Decision (2026-07-06)

Non-custodial. The tracker stores public keys only; private keys never leave the browser.

  1. External wallets via browser extension. The dashboard integrates the standard Solana wallet-adapter flow (Phantom, Solflare, …): connect the extension, prove ownership by signing a nonce, and the verified pubkey is stored as the account wallet. All future transaction authorization (deposits; later, anything requiring a user signature) happens in the extension — the tracker only ever sees signatures and pubkeys.
  2. New wallets generated in-browser. For users without an extension the dashboard generates a keypair client-side (dashboard JS, Ed25519 via WebCrypto or bundled tweetnacl — CSP-safe, no CDN). The pubkey is uploaded; the private key is shown once for export (base58, plaintext acceptable for devnet) with a "save this now" warning, and optionally kept in localStorage for convenience on devnet.
  3. No private-key import. Users cannot paste an existing private key into the dashboard — accepting foreign private keys is a liability the project refuses. Users with existing wallets use the extension path (which imports nothing; it signs in place).

Scope

  • Account panel shows the account wallet address (copy button) or the two attach flows (connect extension / generate in browser)
  • POST /v1/account/wallet — session-authenticated; body carries pubkey and, for the extension flow, the signed-nonce ownership proof (reuse wallet_proof.py if it fits); binds the wallet to the account's keys for deposit attribution (existing bind_wallet path)
  • Wallet is per-account; the tracker fans the binding out to the account's API keys internally
  • Mainnet cutover remains config-only (same boundary as Mock USDT, ADR-0015)

Out of scope: password-wrapped keystore export, hardware wallets, changing the node/miner wallet flow.

Acceptance criteria

  • Connect-extension flow stores a verified pubkey (rejects unsigned/mismatched nonce proofs)
  • Generate flow: pubkey lands on the account; private key is never sent to the tracker (assert no such field in the request), export works
  • No endpoint or UI accepts a private key
  • Deposits to the shown address credit the account's keys via the existing watcher
  • Address visible on the account panel after either flow
  • python -m pytest passes from repo root