Skip to content

Commit c5e4729

Browse files
fix(guardian): keep main's per-account endpoint model after UI-revamp rebase; changelog
1 parent 0bcbb47 commit c5e4729

5 files changed

Lines changed: 19 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Features
66

7+
* [FEATURE][all] **v0 UI revamp.** Refreshes the wallet's visual design across onboarding, home, send, receive, and explore: new typography (Inter body, Nunito headings), brand colors, animated progress/segmented bars, a multi-step send flow (recipient → amount → review), a tabbed receive screen (Address / Pending), and shared UI primitives (`AssetRow`, `SearchInput`, `CardItem`). Guardian selection is unified into a reusable `ChooseGuardianScreen` (also used for switch-guardian) backed by a selectable operator list (`GUARDIAN_OPTIONS`). (#248)
78
* [FEATURE][extension] **New-wallet onboarding hands off to the Chrome side panel.** When creating a wallet, the final onboarding screen creates it while the tab spins ("Creating your wallet…"); once it's ready, the "Open wallet" button opens the side panel onto the finished wallet and closes the onboarding tab. Creating the wallet first means the panel opens from a live user gesture (Chrome requires one for `sidePanel.open()`) onto an already-functional wallet — no loading state in the panel. The side panel also becomes the primary surface (clicking the toolbar icon opens it instead of the popup — toggle back via the header's maximise-view control). Import flows and non-Chrome browsers keep the classic in-tab flow.
89

910
### Fixes

src/lib/miden/back/vault.gaps.test.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,13 +319,6 @@ describe('Vault.spawn: Guardian recovery (lookup + adopt)', () => {
319319
}));
320320

321321
try {
322-
// Guardian recovery now reads the endpoint from storage and throws if
323-
// missing (DEFAULT_GUARDIAN_ENDPOINT is gone), so seed it like the
324-
// onboarding flow does before calling spawn.
325-
const { putToStorage } = await import('../front/storage');
326-
const { GUARDIAN_URL_STORAGE_KEY } = await import('lib/settings/constants');
327-
await putToStorage(GUARDIAN_URL_STORAGE_KEY, 'https://my-guardian.example');
328-
329322
const vault = await Vault.spawn(WalletType.Guardian, 'pw', VALID_MNEMONIC, true);
330323
expect(vault).toBeInstanceOf(Vault);
331324
} finally {

src/lib/miden/back/vault.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from 'lib/miden/back/safe-storage';
2323
import * as Passworder from 'lib/miden/passworder';
2424
import { clearStorage } from 'lib/miden/reset';
25+
import { DEFAULT_GUARDIAN_ENDPOINT } from 'lib/miden-chain/constants';
2526
import { isDesktop, isMobile } from 'lib/platform';
2627
import * as secureHotKey from 'lib/secure-hot-key';
2728
import { GUARDIAN_URL_STORAGE_KEY } from 'lib/settings/constants';
@@ -384,10 +385,8 @@ export class Vault {
384385

385386
if (isGuardianRecovery) {
386387
console.log('[Vault.spawn] Step 7a: recovering Guardian accounts (adopt only — rotation deferred)...');
387-
const guardianEndpoint = await fetchFromStorage<string>(GUARDIAN_URL_STORAGE_KEY);
388-
if (!guardianEndpoint) {
389-
throw new Error('Guardian endpoint missing from storage — wallet must complete guardian onboarding first');
390-
}
388+
const guardianEndpoint =
389+
(await fetchFromStorage<string>(GUARDIAN_URL_STORAGE_KEY)) || DEFAULT_GUARDIAN_ENDPOINT;
391390
const recovered = await midenClient.recoverGuardianAccountsBySeed(
392391
(idx: number) => deriveClientSeed(WalletType.Guardian, mnemonic!, idx),
393392
guardianEndpoint

src/lib/miden/front/guardian-manager.test.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ jest.mock('lib/miden/guardian', () => ({
4242
}
4343
}));
4444

45+
jest.mock('lib/miden-chain/constants', () => ({
46+
DEFAULT_GUARDIAN_ENDPOINT: 'https://default.guardian.test'
47+
}));
48+
4549
jest.mock('lib/settings/constants', () => ({
4650
GUARDIAN_URL_STORAGE_KEY: 'guardian_url_setting'
4751
}));
@@ -103,26 +107,23 @@ describe('guardian-manager', () => {
103107
expect(mockMultisigServiceInit).not.toHaveBeenCalled();
104108
});
105109

106-
it('evicts the cached service when storage is empty on the cache-drift re-check', async () => {
110+
it('falls back to DEFAULT_GUARDIAN_ENDPOINT when storage is empty on the cache-drift re-check', async () => {
107111
// First call seeds the cache with a service pinned to the default endpoint.
108112
const service = { guardianEndpoint: 'https://default.guardian.test', tag: 'cached' };
109113
mockMultisigServiceInit.mockResolvedValueOnce(service);
110114
const provider = makeProvider([guardianAccount]);
111115
await getOrCreateMultisigService(GUARDIAN_PK, provider);
112116

113-
// Second call: storage returns `undefined`. With DEFAULT_GUARDIAN_ENDPOINT
114-
// gone, the cache check requires storage to hold a value — empty storage
115-
// is treated as drift, so the entry is evicted and the service is
116-
// re-initialized.
117-
const refreshed = { guardianEndpoint: 'https://default.guardian.test', tag: 'refreshed' };
117+
// Second call: storage returns `undefined`, so the re-check computes the
118+
// default endpoint via the `|| DEFAULT_GUARDIAN_ENDPOINT` fallback and
119+
// the cached instance stays valid.
118120
mockFetchFromStorage.mockResolvedValueOnce(undefined);
119121
mockMultisigServiceInit.mockClear();
120-
mockMultisigServiceInit.mockResolvedValueOnce(refreshed);
121122

122123
const second = await getOrCreateMultisigService(GUARDIAN_PK, provider);
123124

124-
expect(second).toBe(refreshed);
125-
expect(mockMultisigServiceInit).toHaveBeenCalledTimes(1);
125+
expect(second).toBe(service);
126+
expect(mockMultisigServiceInit).not.toHaveBeenCalled();
126127
});
127128

128129
it('evicts the cached service and reinitializes when the stored guardian URL drifts', async () => {

src/lib/miden/guardian/account.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ jest.mock('../front/storage', () => ({
1919
fetchFromStorage: (...args: unknown[]) => mockFetchFromStorage(...args)
2020
}));
2121

22+
jest.mock('lib/miden-chain/constants', () => ({
23+
DEFAULT_GUARDIAN_ENDPOINT: 'https://default.guardian.test'
24+
}));
25+
2226
jest.mock('lib/settings/constants', () => ({
2327
GUARDIAN_URL_STORAGE_KEY: 'guardian_url_setting'
2428
}));
@@ -198,9 +202,7 @@ describe('createGuardianAccount', () => {
198202
beforeEach(() => {
199203
jest.clearAllMocks();
200204
multisigClientConfig.getPubkey.mockResolvedValue({ commitment: 'g-commit', pubkey: 'g-pubkey' });
201-
// Storage is the source of truth for the guardian endpoint now — return a
202-
// sane value by default so the per-test override paths still work.
203-
mockFetchFromStorage.mockResolvedValue('https://stored.guardian');
205+
mockFetchFromStorage.mockResolvedValue(undefined);
204206
mockGenerateHotKey.mockResolvedValue({
205207
ciphertext: 'hot-ciphertext-hex',
206208
publicKeyHex: 'hot-pubkey-hex',

0 commit comments

Comments
 (0)