Skip to content

refactor: pure-frontend (zero-backend) migration — storage-class + foundation prep [WIP · PAUSED]#400

Draft
jhfnetboy wants to merge 8 commits into
masterfrom
refactor/pure-frontend
Draft

refactor: pure-frontend (zero-backend) migration — storage-class + foundation prep [WIP · PAUSED]#400
jhfnetboy wants to merge 8 commits into
masterfrom
refactor/pure-frontend

Conversation

@jhfnetboy

@jhfnetboy jhfnetboy commented Jul 1, 2026

Copy link
Copy Markdown
Member

WIP / draft — incremental zero-backend migration: remove the NestJS backend so YAA becomes a pure client-side app, then packageable as Chrome MV3 / React Native / single-file widget. Plan: docs/PURE_FRONTEND_MIGRATION.md.

Done — storage-class migrations (no infra needed)

  • ①a Address booklib/address-book-store.ts (localStorage, per-account); transfer records the recipient client-side on confirmation.
  • ①b Token balancelib/token-balance.ts (viem erc20Abi on-chain read); verified live on Sepolia.
  • ①c User token listlib/user-token-store.ts (localStorage; custom-token metadata resolved on-chain).
  • ② Paymaster list + presetslib/paymaster-store.ts (localStorage list + SDK-canonical presets). sponsor was unused; sponsorship stays in the transfer flow (moves in step 4).
  • ③ BLS → removed dead blsAPI (frontend never called it; BLS runs in the transfer flow).
  • Removed from lib/api.ts: addressBookAPI, userTokenAPI, paymasterAPI, blsAPI, tokenAPI.getTokenBalance. Each is per-account-scoped localStorage.

Done — foundation prep (frontend-only, not yet wired)

  • lib/api-key-store.ts — holds the user's AAStar API key + KMS/bundler endpoint overrides.
  • lib/kms-client.ts — direct-KMS seam (kmsBaseUrl / directKmsClient / pingKms) over the existing KmsClient.
  • app/settings/page.tsx — enter/save/test the key (avatar-menu link).

Re-plan (important)

Everything left — account / transfer / guardian / auth — is KMS/auth-rooted (account address + all signatures derive from the user's KMS key via the backend signer). So the order is inverted: the KMS Origin-direct + API-key model + passkey-rooted auth foundation must come first, then account/transfer/guardian move on top, then delete aastar/ + output:'export'. That foundation depends on KMS-side infra (Origin trust for the app + accepting per-user API keys from browsers in production + CORS), not just frontend edits.

Quality

Every step: per-account localStorage or on-chain read, gates green (tsc/lint/format/build), store logic tests, live smoke 200. Self-reviewed (Opus); Opus review caught + fixed an account-timing regression in step 2.

Base automatically changed from feat/tier3-production-webauthn to master July 1, 2026 14:35
@jhfnetboy jhfnetboy force-pushed the refactor/pure-frontend branch from f9d0b1a to 9c03d6c Compare July 1, 2026 14:40
jhfnetboy added 2 commits July 1, 2026 21:46
Anchor doc for incrementally removing the NestJS backend so YAA becomes a pure
client-side app (then packageable as Chrome MV3 / React Native / single-file widget).
Captures the server-only-secret constraints and their zero-backend resolutions
(KMS Origin-direct, public/sponsored bundler, passkey-rooted auth, IndexedDB storage),
a module-by-module destination map, the low-risk-first extraction order, and open
questions (bundler, KMS browser auth, auth model, operator surfaces).
…e store

Replace the backend /address-book* endpoints + JSON store with a per-account
localStorage store (lib/address-book-store.ts) mirroring the old server logic (sort
by usage then recency, keep last 5 tx hashes, case-insensitive match). Transfer + the
address-book page read/write the client store; the transfer flow records the recipient
client-side when polling confirms the tx (replacing the server-side recordSuccessful-
Transfer). addressBookAPI removed from lib/api.ts.

Scope change: address book is now per-AA-account (was per-JWT-user), consistent with
the default-paymaster preference. Backend address-book module left in place for now
(removed in migration step 8). Also records the API-key model (bundler+KMS) in the plan.

11/11 store logic tests pass; tsc/lint/build green.
@jhfnetboy jhfnetboy force-pushed the refactor/pure-frontend branch from 9c03d6c to 58fe81d Compare July 1, 2026 14:46
jhfnetboy added 3 commits July 1, 2026 21:54
…(client-side)

Replace the backend GET /tokens/balance/:address with a direct viem on-chain read
(lib/token-balance.ts: erc20Abi balanceOf/decimals/symbol/name, lazy Sepolia public
client), returning the same TokenBalance shape. transfer + DashboardContext now read
balances client-side; getTokenBalance removed from lib/api.ts. Verified the read path
live on Sepolia (aPNTs: symbol/name/decimals/balanceOf).

getTokenBalance was the only tokenAPI method actually used. The saved-token *list*
(userTokenAPI) is still backend — tracked as step 1c. tsc/lint/format/build green;
dashboard + transfer smoke 200.
…side store

Replace the backend /user-tokens* endpoints + DB with per-account localStorage
(lib/user-token-store.ts). getUserTokens / addUserToken / initializeDefaultTokens are
client-side; a custom token's metadata resolves on-chain (getTokenMetadata added to
token-balance.ts), balances attach via step 1b, and the defaults mirror the old backend
PRESET_TOKENS. TokenSelector + DashboardContext use the store; userTokenAPI removed.

Only getUserTokens/addUserToken/initializeDefaultTokens were ever used (update/remove/
delete/search/reorder were dead). Scope: per-AA-account (was per-JWT-user). Preset
tokens are Optimism contracts — a pre-existing Sepolia-app mismatch preserved verbatim.
8/8 store logic tests; tsc/lint/format/build green; dashboard + transfer smoke 200.
…lient-side

Move the saved paymaster list to per-account localStorage and build the recommended
presets from the SDK canonical table (lib/paymaster-store.ts). The list was only a
frontend picker — paymasterAPI.sponsor was unused and the transfer backend sponsors
from the passed paymasterAddress — so this touches no sponsorship logic (that moves
client-side with the transfer flow, step 4). paymasterAPI removed.

Self-review (Opus) caught + fixed an account-timing regression: the now account-scoped
saved list was read once at mount, so a fresh load beating the async account fetch left
it empty with no reload. Transfer now (re)loads it in an effect keyed on account.address;
the Paymaster page's load effect gained the accountAddress dep. (TokenSelector already
keyed loadTokens on accountAddress.)

8/8 store logic tests; tsc/lint/format/build green; paymaster + transfer + dashboard 200.
function save(account: string | null | undefined, list: StoredPaymaster[]): void {
if (typeof window === "undefined") return;
try {
window.localStorage.setItem(storageKey(account), JSON.stringify(list));
jhfnetboy added 2 commits July 1, 2026 22:24
…uth first)

blsAPI was never called by the frontend (BLS runs in the backend transfer flow), so it's
removed as dead code; the real BLS moves client-side with the transfer migration.

Re-planning: the account operations (getAccount/create) are KMS/auth-rooted — the account
address and signatures derive from the user's KMS key via the backend signer, so account/
transfer/guardian can't move to the browser until the KMS/auth foundation exists. The plan
doc now inverts the order: KMS Origin-direct + API-key model + passkey-rooted auth come
FIRST, then account/transfer/guardian build on top. That foundation depends on real KMS
Origin-auth infra (not just a frontend edit).
…m + Settings

Frontend-only groundwork for the zero-backend KMS/auth foundation, done ahead of the
infra and deliberately NOT wired into any flow (non-breaking):
- lib/api-key-store.ts: hold the user's AAStar API key + optional KMS/bundler endpoint
  overrides in localStorage (the key that will authorize direct browser->KMS/bundler).
- lib/kms-client.ts: extend the existing KmsClient with a direct-KMS seam — kmsBaseUrl(),
  isDirectKmsReady(), directKmsClient() (wires KmsClient to the user's key), pingKms().
- app/settings/page.tsx (+ avatar-menu link): enter/save/clear the key + endpoint
  overrides, test KMS connectivity, show direct-ready status. pingKms CORS-fails until KMS
  allows the browser Origin — that failure is itself the readiness signal.

Auth/transfer still use the /kms-api proxy; these switch over once the KMS Origin+API-key
path is live. lib/auth.ts already centralizes the JWT, so no convergence needed there.
tsc/lint/format/build green; /settings + /dashboard smoke 200.
function set(key: string, value: string): void {
if (typeof window === "undefined") return;
try {
window.localStorage.setItem(key, value);
@jhfnetboy jhfnetboy changed the title refactor: pure-frontend (zero-backend) migration [WIP] refactor: pure-frontend (zero-backend) migration — storage-class + foundation prep [WIP] Jul 1, 2026
Consolidate the migration record: overall ~25% (storage-class + foundation prep done;
core auth/account/transfer/guardian blocked on infra), a Done/Left summary, and a new
'Infra requirements' section for the KMS/bundler teams — Origin trust for non-aastar.io
shells, production per-user-API-key auth, CORS, and the same for the bundler. Branch is
paused until that infra lands.
@jhfnetboy jhfnetboy changed the title refactor: pure-frontend (zero-backend) migration — storage-class + foundation prep [WIP] refactor: pure-frontend (zero-backend) migration — storage-class + foundation prep [WIP · PAUSED] Jul 1, 2026
@jhfnetboy

Copy link
Copy Markdown
Member Author

Paused (2026-07-01). Storage-class migrations + frontend foundation prep are done (~25% overall). The remaining core (auth / account / transfer / guardian) is KMS/auth-rooted and blocked on KMS/bundler infra that doesn't exist yet — see the Infra requirements section in docs/PURE_FRONTEND_MIGRATION.md (Origin trust for non-aastar.io shells, production per-user-API-key auth, CORS, same for the bundler). Resuming once that infra lands and other priorities clear. Branch stays open as draft.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants