-
Notifications
You must be signed in to change notification settings - Fork 10
Description
Summary
API keys are stored in two layers: on-chain (smart contract token slots 0-254) and browser localStorage (key strings, labels, expiry). localStorage is origin-scoped, so keys generated from one origin (e.g., localhost:3090) are invisible from another origin (e.g., hosted deployment). The WebUI does not warn users about this, leading to potential silent key invalidation.
Actual behavior
When a user generates an API key on Origin A, then accesses the WebUI from Origin B:
- SlotManager shows the occupied slot as "available" (white circle) —
useSlotStatus.ts:138-147treats no-localData + not-revoked asavailable - SlotStatusCompact shows "0 active, 255 available" —
activeonly counts slots withlocalData - ProviderApiKeyManager shows "0 existing keys" — reads from localStorage only
- Key generation can silently overwrite the Origin A key —
findNextAvailableTokenIdFromData(useSlotStatus.ts:209-213) only checks localStorage for slot occupancy, not on-chain state - BuildDrawer Step 3 shows "incomplete" even though on-chain slot is occupied
The only component that correctly identifies the gap is OnChainTokensView (OnChainTokensView.tsx:69-71), which shows "Unknown" tokens with an amber badge — but this view is buried in the wallet page, not shown during key generation.
Expected behavior
- Slots with on-chain activity but no localStorage data should show as "unknown" (not "available")
- A warning banner should appear when the system detects potential external keys (generation counter > 0 but no local keys)
- Key generation should warn before potentially overwriting a slot that may have an active key from another origin
- Slot grid should visually distinguish "unknown" slots from truly "available" ones
Root cause
useSlotStatus.ts:138-147 explicitly documents the ambiguity in a comment but defaults to treating unknown slots as available:
// Not revoked but no local data - could be:
// 1. Never used (available)
// 2. Used but localStorage lost (unknown)
// For slot visualization, we treat it as available unless we know it's occupied
The on-chain contract only tracks revokedBitmap (revoked/not-revoked), not whether a slot was ever used. Without a separate "used bitmap" or off-chain sync, the UI cannot definitively distinguish "never used" from "used elsewhere." However, the generation counter and local key count provide a reliable heuristic.
Proposed fix
A UX-only fix (no contract changes) in 3 phases:
Phase 1 — Detection layer:
- Add
externalSlotCounttouseOnChainTokens.tsreturn value (heuristic: non-revoked, no localData, AND generation > 0 or has some local keys) - Add
unknowncount toSlotStatsinuseSlotStatus.ts
Phase 2 — Warning UI:
- Add amber warning banner to
ProviderApiKeyManager.tsxwhen external keys are detected - Add confirm dialog before key generation when generation > 0 and no local keys exist
- Add "may have external keys" indicator to
SlotStatusCompact.tsx
Phase 3 — Slot grid visualization:
- Add
unknownslot status type touseSlotStatus.ts - Render unknown slots with distinct color (amber) in
SlotManager.tsx - Update legend to include "Unknown (possible external key)"
Will submit a PR with the implementation.
Repro notes
- Run WebUI on
localhost:3090, connect wallet, generate an API key - Note which slot was assigned (e.g., slot 0)
- Open WebUI on a different origin (or clear localStorage)
- Connect same wallet — slot 0 shows as "available" instead of warning
- Generate a new key — it may reuse slot 0, silently invalidating the first key