Repository navigation
feat: key deployments by chain id and address - #67
Conversation
Add deploymentKey(chainId, address) to typewriter/client. The runtime
uses it for the Postgres schema name, and the token and order-book
frontends use it as the browser storage key. Before this change, the
order-book frontend used the address only, so deployments on different
chains with the same address shared browser accounts.
deploymentSchemaName throws when the name exceeds 63 characters,
because Postgres truncates longer identifiers without an error.
Give the token and order-book frontends the same account management:
- lib/account-store.ts stores { accountId, keyPair } as one IndexedDB
record, so a write cannot leave part of an account behind.
- hooks/useManifest and hooks/useStoredAccount thinly wrap useQuery.
Mutations update the stored account with setQueryData.
- Each session signs on a random nonce lane, so the nonce is not
stored and two tabs cannot use the same nonce.
- Signing keys are not extractable.
- lib/api.ts is shared, and reads plain-text error bodies.
Order book drops its manifest and account contexts and the unused
sign-in hook, signs with the session credential (ID 1), and gets a
sign-out mutation that deletes the stored account.
| onSuccess: async (result) => { | ||
| queryClient.setQueryData(["storedAccount", storageKey], result.account); |
There was a problem hiding this comment.
If a user signs out while an order is pending, this callback restores the captured account, including its signing keys, when the order succeeds. The sign-out button stays available during the request. Unlike the old null-preserving update, this replaces the whole account, so the page can sign more orders without another sign-in.
Update the cache only if it still holds the same session. Apply the same guard in useDepositMutation.
How this was verified: Sign-out clears the cached account, but a pending order’s success callback restores the captured keys that subsequent orders use to sign.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/order-book/frontend/hooks/useMarketOrderMutation.ts
Line: 49-50
Comment:
**Sign-out gets undone**
If a user signs out while an order is pending, this callback restores the captured account, including its signing keys, when the order succeeds. The sign-out button stays available during the request. Unlike the old null-preserving update, this replaces the whole account, so the page can sign more orders without another sign-in.
Update the cache only if it still holds the same session. Apply the same guard in `useDepositMutation`.
**How this was verified:** Sign-out clears the cached account, but a pending order’s success callback restores the captured keys that subsequent orders use to sign.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| const stored = { accountId, keyPair }; | ||
| await saveStoredAccount(storageKey, stored); |
There was a problem hiding this comment.
The token app now saves the account before submitting Mint. If that request fails before acceptance, reloading loads the saved account with no tokens and hides the only sign-in button. The signed-in page has no mint retry or sign-out action, so the user cannot finish setup without clearing browser storage.
Save the account after Mint succeeds, or keep a recoverable setup state with a retry action.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/token/frontend/App.tsx
Line: 229-230
Comment:
**Failed setup cannot recover**
The token app now saves the account before submitting `Mint`. If that request fails before acceptance, reloading loads the saved account with no tokens and hides the only sign-in button. The signed-in page has no mint retry or sign-out action, so the user cannot finish setup without clearing browser storage.
Save the account after `Mint` succeeds, or keep a recoverable setup state with a retry action.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Summary
deploymentKey(chainId, address)totypewriter/client. The runtime uses it for the Postgres schema name. The token and order-book frontends use it as the browser storage key. Before this change, order-book used the address only, so deployments on different chains with the same address shared browser accounts.deploymentSchemaNamethrows when the name is longer than 63 characters, because Postgres truncates longer identifiers without an error.lib/account-store.tsstores{ accountId, keyPair }as one IndexedDB record.hooks/useManifestandhooks/useStoredAccountthinly wrapuseQuery. Mutations update the stored account withsetQueryData.lib/api.tsis shared, and reads plain-text error bodies.Notes
Test plan
bun run typecheckin each app and packagebunx biome checkpackages/typewriter: client, migrate and db-query tests pass🤖 Generated with Claude Code
Fix the sign-out race and failed token setup recovery before merging.
Fix with agent prompt
Summary
This PR shares deployment keys across Postgres and browser storage, and moves both frontends to account records in IndexedDB.
Acknowledged by
kyscott18: existing saved accounts must sign in again because storage changes. Also explicitly deferred bykyscott18: restarting anvil can reuse an address and conflict with old Postgres schemas and IndexedDB records.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD M[Manifest: chain ID and address] --> K[deploymentKey] K --> P[Postgres schema name] K --> I[IndexedDB account record] I --> Q[React Query account cache] Q --> S[Sign order] S --> R[Request pending] Q --> O[Sign out] O --> C[Delete record and clear cache] R --> F[Order succeeds] F --> B[Captured account replaces cache] B --> QReviews (1) · Last reviewed commit: "feat: key deployments by chain id and ad..." · Reviewed by Greptile