@vaultkeepr/smart-account 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -162,252 +162,102 @@ function clearSmartAccountCache() {
162
162
  _cachedKey = null;
163
163
  }
164
164
 
165
- // src/owner.ts
166
- import { getHiddenWalletFromPassword, getHiddenWalletLegacy } from "@vaultkeepr/core";
167
- async function getOwnerFromPassword(password, secretKey) {
168
- return getHiddenWalletFromPassword(password, secretKey);
169
- }
170
-
171
- // src/cidRegistry.ts
165
+ // src/deriveIdentity.ts
172
166
  import {
173
167
  createPublicClient as createPublicClient2,
174
- encodeFunctionData,
175
- http as http2
168
+ http as http2,
169
+ getAddress,
170
+ isAddressEqual,
171
+ recoverMessageAddress,
172
+ zeroAddress
176
173
  } from "viem";
177
- import { logger as logger2 } from "@vaultkeepr/logger";
178
- var CID_REGISTRY_ABI = [
179
- {
180
- name: "setCid",
181
- type: "function",
182
- stateMutability: "nonpayable",
183
- inputs: [{ name: "cid", type: "string" }],
184
- outputs: []
185
- },
186
- {
187
- name: "deleteCid",
188
- type: "function",
189
- stateMutability: "nonpayable",
190
- inputs: [],
191
- outputs: []
192
- },
193
- {
194
- name: "getCid",
195
- type: "function",
196
- stateMutability: "view",
197
- inputs: [{ name: "account", type: "address" }],
198
- outputs: [{ name: "", type: "string" }]
199
- },
200
- {
201
- name: "hasCid",
202
- type: "function",
203
- stateMutability: "view",
204
- inputs: [{ name: "account", type: "address" }],
205
- outputs: [{ name: "", type: "bool" }]
206
- },
207
- {
208
- name: "getUpdatedAt",
209
- type: "function",
210
- stateMutability: "view",
211
- inputs: [{ name: "account", type: "address" }],
212
- outputs: [{ name: "", type: "uint256" }]
213
- },
214
- {
215
- name: "nextAllowedUpdate",
216
- type: "function",
217
- stateMutability: "view",
218
- inputs: [{ name: "account", type: "address" }],
219
- outputs: [{ name: "", type: "uint256" }]
220
- },
221
- {
222
- name: "cooldownSeconds",
223
- type: "function",
224
- stateMutability: "view",
225
- inputs: [],
226
- outputs: [{ name: "", type: "uint256" }]
227
- }
228
- ];
229
- function getCidRegistryAddress() {
230
- let addr = "";
231
- try {
232
- addr = process.env.CID_REGISTRY_ADDRESS || "";
233
- } catch {
234
- }
235
- if (addr) return addr;
236
- try {
237
- addr = process.env.NEXT_PUBLIC_CID_REGISTRY_ADDRESS || "";
238
- } catch {
239
- }
240
- if (addr) return addr;
241
- try {
242
- addr = process.env.EXPO_PUBLIC_CID_REGISTRY_ADDRESS || "";
243
- } catch {
244
- }
245
- if (addr) return addr;
246
- return "0x0000000000000000000000000000000000000000";
174
+ async function deriveIdentity(ownerAccount, mode) {
175
+ const aaAddress = await computeSmartAccountAddress(ownerAccount);
176
+ return {
177
+ ownerAddress: ownerAccount.address,
178
+ aaAddress,
179
+ mode
180
+ };
247
181
  }
248
- function isCidRegistryConfigured() {
249
- return getCidRegistryAddress() !== "0x0000000000000000000000000000000000000000" && isSmartAccountConfigured();
182
+ var MAX_SKEW_MS = 5 * 6e4;
183
+ var UNSIGNABLE_OWNER = "verifyAAAuth: owner stub cannot sign";
184
+ function addressOnlyAccount(address) {
185
+ return {
186
+ address,
187
+ type: "local",
188
+ publicKey: "0x",
189
+ source: "custom",
190
+ signMessage: async () => {
191
+ throw new Error(UNSIGNABLE_OWNER);
192
+ },
193
+ signTypedData: async () => {
194
+ throw new Error(UNSIGNABLE_OWNER);
195
+ },
196
+ signTransaction: async () => {
197
+ throw new Error(UNSIGNABLE_OWNER);
198
+ }
199
+ };
250
200
  }
251
- async function publishCidOnChain(smartAccount, cid) {
252
- if (!isCidRegistryConfigured()) {
253
- logger2.warn(
254
- "[CidRegistry] Non configur\xE9, skip on-chain publish"
255
- );
256
- return null;
257
- }
201
+ async function verifyAAAuth(params) {
202
+ const rejected = {
203
+ ok: false,
204
+ ownerAddress: zeroAddress,
205
+ aaAddress: zeroAddress
206
+ };
258
207
  try {
259
- const calldata = encodeFunctionData({
260
- abi: CID_REGISTRY_ABI,
261
- functionName: "setCid",
262
- args: [cid]
263
- });
264
- const userOpHash = await smartAccount.client.sendUserOperation({
265
- calls: [
266
- {
267
- to: getCidRegistryAddress(),
268
- data: calldata,
269
- value: BigInt(0)
270
- }
271
- ]
272
- });
273
- logger2.debug(
274
- `[CidRegistry] UserOp soumise: ${userOpHash}`
275
- );
276
- const receipt = await smartAccount.client.waitForUserOperationReceipt({
277
- hash: userOpHash
278
- });
279
- logger2.debug(
280
- `[CidRegistry] CID publi\xE9 on-chain \u2014 tx: ${receipt.receipt.transactionHash} | CID: ${cid.slice(0, 20)}...`
208
+ if (!Number.isFinite(params.timestamp) || Math.abs(Date.now() - params.timestamp) > MAX_SKEW_MS) {
209
+ return rejected;
210
+ }
211
+ const signature = params.signature;
212
+ let ownerAddress;
213
+ if (params.claimedOwner) {
214
+ ownerAddress = getAddress(params.claimedOwner);
215
+ const publicClient = createPublicClient2({
216
+ chain: TARGET_CHAIN,
217
+ transport: http2()
218
+ });
219
+ const valid = await publicClient.verifyMessage({
220
+ address: ownerAddress,
221
+ message: params.message,
222
+ signature
223
+ });
224
+ if (!valid) {
225
+ return {
226
+ ok: false,
227
+ ownerAddress,
228
+ aaAddress: params.claimedAA ? getAddress(params.claimedAA) : zeroAddress
229
+ };
230
+ }
231
+ } else {
232
+ ownerAddress = await recoverMessageAddress({
233
+ message: params.message,
234
+ signature
235
+ });
236
+ }
237
+ const claimedAA = params.claimedAA ? getAddress(params.claimedAA) : null;
238
+ const aaAddress = await computeSmartAccountAddress(
239
+ addressOnlyAccount(ownerAddress)
281
240
  );
282
- return receipt.receipt.transactionHash;
283
- } catch (error) {
284
- logger2.error("[CidRegistry] Erreur:", error instanceof Error ? error.message : error);
285
- return null;
286
- }
287
- }
288
- async function readCidOnChain(smartAccountAddress) {
289
- if (!isCidRegistryConfigured()) return null;
290
- try {
291
- const publicClient = createPublicClient2({
292
- chain: TARGET_CHAIN,
293
- transport: http2()
294
- });
295
- const cid = await publicClient.readContract({
296
- address: getCidRegistryAddress(),
297
- abi: CID_REGISTRY_ABI,
298
- functionName: "getCid",
299
- args: [smartAccountAddress]
300
- });
301
- return cid && cid.length > 0 ? cid : null;
302
- } catch (error) {
303
- logger2.error("[CidRegistry] Erreur lecture:", error instanceof Error ? error.message : error);
304
- return null;
241
+ if (claimedAA && !isAddressEqual(claimedAA, aaAddress)) {
242
+ return { ok: false, ownerAddress, aaAddress };
243
+ }
244
+ return { ok: true, ownerAddress, aaAddress };
245
+ } catch {
246
+ return rejected;
305
247
  }
306
248
  }
307
249
 
308
- // src/onChainSync.ts
309
- import { logger as logger3 } from "@vaultkeepr/logger";
310
- var DEFAULT_DEBOUNCE_MS = 5 * 60 * 1e3;
311
- var _pendingCid = null;
312
- var _pendingSmartAccount = null;
313
- var _debounceTimer = null;
314
- var _lastPublishedCid = null;
315
- var _lastPublishTime = 0;
316
- var _isPublishing = false;
317
- function scheduleCidOnChainSync(smartAccount, cid, debounceMs = DEFAULT_DEBOUNCE_MS) {
318
- if (!isCidRegistryConfigured()) return;
319
- if (cid === _lastPublishedCid) {
320
- logger3.debug("[OnChainSync] CID identique, skip");
321
- return;
322
- }
323
- const sa = smartAccount ?? _pendingSmartAccount;
324
- if (!sa) {
325
- logger3.warn("[OnChainSync] Pas de Smart Account disponible, skip");
326
- return;
327
- }
328
- _pendingCid = cid;
329
- _pendingSmartAccount = sa;
330
- if (_debounceTimer) {
331
- clearTimeout(_debounceTimer);
332
- }
333
- _debounceTimer = setTimeout(() => {
334
- _executeSync();
335
- }, debounceMs);
336
- logger3.debug(
337
- `[OnChainSync] CID planifi\xE9 dans ${(debounceMs / 1e3).toFixed(0)}s : ${cid.slice(0, 20)}...`
338
- );
339
- }
340
- async function flushCidOnChainSync() {
341
- logger3.debug(
342
- "[OnChainSync] flush demand\xE9 \u2014 pending:",
343
- _pendingCid?.slice(0, 20),
344
- "SA:",
345
- !!_pendingSmartAccount
346
- );
347
- if (!_pendingCid || !_pendingSmartAccount) {
348
- logger3.debug("[OnChainSync] Rien \xE0 flush");
349
- return true;
350
- }
351
- if (_debounceTimer) {
352
- clearTimeout(_debounceTimer);
353
- _debounceTimer = null;
354
- }
355
- logger3.debug("[OnChainSync] Flush imm\xE9diat...");
356
- return _executeSync();
357
- }
358
- function getOnChainSyncStatus() {
359
- return {
360
- hasPending: _pendingCid !== null && _pendingCid !== _lastPublishedCid,
361
- pendingCid: _pendingCid,
362
- lastPublishedCid: _lastPublishedCid,
363
- lastPublishTime: _lastPublishTime,
364
- isPublishing: _isPublishing
365
- };
366
- }
367
- function resetOnChainSync() {
368
- if (_debounceTimer) {
369
- clearTimeout(_debounceTimer);
370
- _debounceTimer = null;
371
- }
372
- _pendingCid = null;
373
- _pendingSmartAccount = null;
374
- _lastPublishedCid = null;
375
- _lastPublishTime = 0;
376
- _isPublishing = false;
377
- }
378
- async function _executeSync() {
379
- if (!_pendingCid || !_pendingSmartAccount || _isPublishing) return false;
380
- if (_pendingCid === _lastPublishedCid) {
381
- _pendingCid = null;
382
- return true;
383
- }
384
- _isPublishing = true;
385
- const cid = _pendingCid;
386
- const sa = _pendingSmartAccount;
387
- try {
388
- logger3.debug(`[OnChainSync] Publication on-chain: ${cid.slice(0, 20)}...`);
389
- const txHash = await publishCidOnChain(sa, cid);
390
- if (txHash) {
391
- _lastPublishedCid = cid;
392
- _lastPublishTime = Date.now();
393
- _pendingCid = null;
394
- logger3.debug(
395
- `[OnChainSync] \u2705 CID publi\xE9 on-chain : ${cid.slice(0, 20)}...`
396
- );
397
- return true;
398
- }
399
- logger3.warn("[OnChainSync] Publication \xE9chou\xE9e (null txHash)");
400
- return false;
401
- } catch (error) {
402
- logger3.error("[OnChainSync] Erreur publication:", error instanceof Error ? error.message : error);
403
- return false;
404
- } finally {
405
- _isPublishing = false;
250
+ // src/owner.ts
251
+ import { getHiddenWalletFromPassword, getHiddenWalletFromSecretKey, getHiddenWalletLegacy } from "@vaultkeepr/core";
252
+ async function getOwnerFromPassword(password, secretKey) {
253
+ if (secretKey) {
254
+ return getHiddenWalletFromSecretKey(secretKey);
406
255
  }
256
+ return getHiddenWalletFromPassword(password);
407
257
  }
408
258
 
409
259
  // src/identity.ts
410
- import { logger as logger4, redactAddress as redactAddress2 } from "@vaultkeepr/logger";
260
+ import { logger as logger2, redactAddress as redactAddress2 } from "@vaultkeepr/logger";
411
261
  var _state = {
412
262
  owner: null,
413
263
  smartAccount: null,
@@ -433,7 +283,15 @@ async function initIdentityFromPassword(password, secretKey) {
433
283
  mode: "password"
434
284
  });
435
285
  } catch (e) {
436
- logger4.warn("[Identity] SA init failed (non-blocking):", e.message);
286
+ logger2.warn("[Identity] SA init failed (non-blocking):", e.message);
287
+ }
288
+ }
289
+ let aaAddress = sa?.address ?? null;
290
+ if (!aaAddress && isSmartAccountConfigured()) {
291
+ try {
292
+ aaAddress = await computeSmartAccountAddress(owner);
293
+ } catch (e) {
294
+ logger2.warn("[Identity] AA derivation failed (non-blocking):", e.message);
437
295
  }
438
296
  }
439
297
  _state = {
@@ -443,12 +301,13 @@ async function initIdentityFromPassword(password, secretKey) {
443
301
  initialized: true
444
302
  };
445
303
  _notify();
446
- logger4.debug(
304
+ logger2.debug(
447
305
  `[Identity] Connect\xE9 (password) \u2014 adresse: ${redactAddress2(owner.address)}` + (sa ? ` | SA: ${redactAddress2(sa.address)}` : "") + (secretKey ? ` | SK: \u2713` : " | no secretKey")
448
306
  );
449
307
  return {
450
308
  address: owner.address,
451
- smartAccountAddress: sa?.address ?? null
309
+ smartAccountAddress: sa?.address ?? null,
310
+ aaAddress
452
311
  };
453
312
  }
454
313
  async function initIdentityFromSigner(signer, mode = "passkey") {
@@ -457,7 +316,15 @@ async function initIdentityFromSigner(signer, mode = "passkey") {
457
316
  try {
458
317
  sa = await createVaultSmartAccount({ ownerAccount: signer, mode });
459
318
  } catch (e) {
460
- logger4.warn("[Identity] SA init failed (non-blocking):", e.message);
319
+ logger2.warn("[Identity] SA init failed (non-blocking):", e.message);
320
+ }
321
+ }
322
+ let aaAddress = sa?.address ?? null;
323
+ if (!aaAddress && isSmartAccountConfigured()) {
324
+ try {
325
+ aaAddress = await computeSmartAccountAddress(signer);
326
+ } catch (e) {
327
+ logger2.warn("[Identity] AA derivation failed (non-blocking):", e.message);
461
328
  }
462
329
  }
463
330
  _state = {
@@ -467,12 +334,13 @@ async function initIdentityFromSigner(signer, mode = "passkey") {
467
334
  initialized: true
468
335
  };
469
336
  _notify();
470
- logger4.info(
337
+ logger2.info(
471
338
  `[Identity] Connected (${mode}) \u2014 address: ${signer.address}` + (sa ? ` | SA: ${sa.address}` : "")
472
339
  );
473
340
  return {
474
341
  address: signer.address,
475
- smartAccountAddress: sa?.address ?? null
342
+ smartAccountAddress: sa?.address ?? null,
343
+ aaAddress
476
344
  };
477
345
  }
478
346
  function clearIdentity() {
@@ -484,7 +352,7 @@ function clearIdentity() {
484
352
  };
485
353
  clearSmartAccountCache();
486
354
  _notify();
487
- logger4.info("[Identity] Disconnected");
355
+ logger2.info("[Identity] Disconnected");
488
356
  }
489
357
  function getIdentityAddress() {
490
358
  return _state.owner?.address ?? null;
@@ -543,24 +411,10 @@ function useIdentity() {
543
411
  const disconnect = useCallback(() => {
544
412
  clearIdentity();
545
413
  }, []);
546
- const notifyOnChainSync = useCallback(
547
- (cid) => {
548
- const sa = getIdentitySmartAccount();
549
- if (!sa) return;
550
- scheduleCidOnChainSync(sa, cid);
551
- },
552
- []
553
- );
554
- const cleanupOnLock = useCallback(async () => {
555
- await flushCidOnChainSync().catch(() => {
556
- });
414
+ const cleanupOnLock = useCallback(() => {
557
415
  clearSmartAccountCache();
558
- resetOnChainSync();
559
416
  clearIdentity();
560
- }, []);
561
- const flushOnChainSync = useCallback(async () => {
562
- await flushCidOnChainSync().catch(() => {
563
- });
417
+ return Promise.resolve();
564
418
  }, []);
565
419
  return {
566
420
  address: state.owner?.address ?? null,
@@ -569,9 +423,7 @@ function useIdentity() {
569
423
  smartAccountAddress: state.smartAccount?.address ?? null,
570
424
  signMessage,
571
425
  disconnect,
572
- notifyOnChainSync,
573
- cleanupOnLock,
574
- flushOnChainSync
426
+ cleanupOnLock
575
427
  };
576
428
  }
577
429
 
@@ -579,13 +431,12 @@ function useIdentity() {
579
431
  import { bytesToHex } from "viem";
580
432
  function generateSecretKey() {
581
433
  const bytes = new Uint8Array(32);
582
- if (typeof globalThis.crypto?.getRandomValues === "function") {
583
- globalThis.crypto.getRandomValues(bytes);
584
- } else {
585
- for (let i = 0; i < 32; i++) {
586
- bytes[i] = Math.floor(Math.random() * 256);
587
- }
434
+ if (typeof globalThis.crypto?.getRandomValues !== "function") {
435
+ throw new Error(
436
+ "[SmartAccount] CSPRNG indisponible: crypto.getRandomValues est requis pour generer une cle secrete. Un fallback Math.random produirait une cle devinable (CWE-338), refuse."
437
+ );
588
438
  }
439
+ globalThis.crypto.getRandomValues(bytes);
589
440
  return bytesToHex(bytes).slice(2);
590
441
  }
591
442
  function isValidSecretKey(key) {
@@ -598,13 +449,214 @@ function formatSecretKeyForDisplay(key) {
598
449
  function parseSecretKeyInput(input) {
599
450
  return input.replace(/[-\s]/g, "").toLowerCase();
600
451
  }
452
+
453
+ // src/keyPassage.ts
454
+ function identityState(input) {
455
+ if (input.hasSecretKey) return { kind: "ready" };
456
+ if (input.pointer === "moved") return { kind: "pair_required" };
457
+ if (input.pointer === "active") return { kind: "pass_to_key" };
458
+ return { kind: "join_or_create" };
459
+ }
460
+ function canWritePointer(state) {
461
+ return state.kind === "ready" || state.kind === "pass_to_key";
462
+ }
463
+ function sameAddress(a, b) {
464
+ return a.trim().toLowerCase() === b.trim().toLowerCase();
465
+ }
466
+ async function runPassage(io, opts) {
467
+ if (opts.hasSecretKey) return { status: "already_keyed" };
468
+ const legacy = await io.readLegacyPointer();
469
+ if (legacy.moved) {
470
+ const pending = await io.peekPendingKey();
471
+ if (pending && legacy.movedTo && sameAddress(await io.smartAccountOf(pending), legacy.movedTo)) {
472
+ await io.activatePendingKey();
473
+ return { status: "moved", smartAccount: legacy.movedTo };
474
+ }
475
+ if (pending) await io.discardPendingKey();
476
+ return { status: "already_moved" };
477
+ }
478
+ if (!legacy.cid) return { status: "nothing_to_pass" };
479
+ const secretKey = await io.getOrCreatePendingKey();
480
+ const smartAccount = await io.smartAccountOf(secretKey);
481
+ await io.writeSmartAccountPointer(smartAccount, legacy.cid);
482
+ await io.markLegacyMoved(smartAccount);
483
+ await io.activatePendingKey();
484
+ return { status: "moved", smartAccount };
485
+ }
486
+
487
+ // src/passageClient.ts
488
+ var PASSAGE_ENABLED = false;
489
+ var DELEGATION_TTL_SECONDS = 300;
490
+ async function postJson(env, path, body) {
491
+ const res = await env.fetch(`${env.apiBase}${path}`, {
492
+ method: "POST",
493
+ headers: { "Content-Type": "application/json" },
494
+ body: JSON.stringify(body)
495
+ });
496
+ if (!res.ok) throw new Error(`passage ${path} failed (${res.status})`);
497
+ return res.json();
498
+ }
499
+ function createPassageIO(env) {
500
+ const legacyAddress = env.legacyAddress.toLowerCase();
501
+ const delegation2 = async (sign) => {
502
+ const sessionId = env.newSessionId();
503
+ const expiryTimestamp = Math.floor(env.now() / 1e3) + DELEGATION_TTL_SECONDS;
504
+ const delegationSignature = await sign(env.formatDelegation(sessionId, expiryTimestamp));
505
+ return { sessionId, expiryTimestamp, delegationSignature };
506
+ };
507
+ return {
508
+ async readLegacyPointer() {
509
+ const d = await delegation2((m) => env.signLegacy(m));
510
+ const query = [
511
+ `wallet=${encodeURIComponent(legacyAddress)}`,
512
+ `delegationSignature=${encodeURIComponent(d.delegationSignature)}`,
513
+ `sessionId=${encodeURIComponent(d.sessionId)}`,
514
+ `expiryTimestamp=${d.expiryTimestamp}`
515
+ ].join("&");
516
+ const res = await env.fetch(`${env.apiBase}/api/vault-cid?${query}`);
517
+ if (!res.ok) throw new Error(`passage read failed (${res.status})`);
518
+ const json = await res.json();
519
+ return { cid: json.cid ?? null, moved: !!json.moved, movedTo: json.movedTo ?? void 0 };
520
+ },
521
+ peekPendingKey: () => env.pending.read(),
522
+ async getOrCreatePendingKey() {
523
+ const existing = await env.pending.read();
524
+ if (existing) return existing;
525
+ const secretKey = env.newSecretKey();
526
+ await env.pending.write(secretKey);
527
+ return secretKey;
528
+ },
529
+ smartAccountOf: (secretKey) => env.smartAccountOf(secretKey),
530
+ async writeSmartAccountPointer(smartAccount, cid) {
531
+ const pendingKey = await env.pending.read();
532
+ if (!pendingKey) throw new Error("passage: no pending key");
533
+ const d = await delegation2((m) => env.signWithKey(pendingKey, m));
534
+ await postJson(env, "/api/vault-cid", {
535
+ walletAddress: smartAccount,
536
+ cid,
537
+ delegationSignature: d.delegationSignature,
538
+ sessionId: d.sessionId,
539
+ expiryTimestamp: d.expiryTimestamp
540
+ });
541
+ },
542
+ async markLegacyMoved(smartAccount) {
543
+ const d = await delegation2((m) => env.signLegacy(m));
544
+ await postJson(env, "/api/vault-cid/move", {
545
+ walletAddress: legacyAddress,
546
+ targetSmartAccount: smartAccount,
547
+ delegationSignature: d.delegationSignature,
548
+ sessionId: d.sessionId,
549
+ expiryTimestamp: d.expiryTimestamp
550
+ });
551
+ },
552
+ async activatePendingKey() {
553
+ const pendingKey = await env.pending.read();
554
+ if (!pendingKey) throw new Error("passage: no pending key");
555
+ await env.activate(pendingKey);
556
+ await env.pending.clear();
557
+ },
558
+ discardPendingKey: () => env.pending.clear()
559
+ };
560
+ }
561
+ async function readPassageState(env, hasSecretKey) {
562
+ const legacy = await createPassageIO(env).readLegacyPointer();
563
+ const pointer = legacy.moved ? "moved" : legacy.cid ? "active" : "none";
564
+ return identityState({ hasSecretKey, pointer });
565
+ }
566
+ function runPassageWith(env, hasSecretKey) {
567
+ return runPassage(createPassageIO(env), { hasSecretKey });
568
+ }
569
+
570
+ // src/keyedMigration.ts
571
+ var KEYED_MIGRATION_ENABLED = false;
572
+ var DELEGATION_TTL_SECONDS2 = 300;
573
+ async function delegation(env) {
574
+ const sessionId = env.newSessionId();
575
+ const expiryTimestamp = Math.floor(env.now() / 1e3) + DELEGATION_TTL_SECONDS2;
576
+ const delegationSignature = await env.signWithKey(env.formatDelegation(sessionId, expiryTimestamp));
577
+ return { sessionId, expiryTimestamp, delegationSignature };
578
+ }
579
+ async function readPointer(env, wallet) {
580
+ const d = await delegation(env);
581
+ const query = [
582
+ `wallet=${encodeURIComponent(wallet)}`,
583
+ `delegationSignature=${encodeURIComponent(d.delegationSignature)}`,
584
+ `sessionId=${encodeURIComponent(d.sessionId)}`,
585
+ `expiryTimestamp=${d.expiryTimestamp}`
586
+ ].join("&");
587
+ const res = await env.fetch(`${env.apiBase}/api/vault-cid?${query}`);
588
+ if (!res.ok) throw new Error(`keyed migration: read failed (${res.status})`);
589
+ const json = await res.json();
590
+ return { cid: json.cid ?? null, moved: !!json.moved, movedTo: json.movedTo ?? void 0 };
591
+ }
592
+ async function copyPointer(env, smartAccount, cid) {
593
+ const d = await delegation(env);
594
+ const res = await env.fetch(`${env.apiBase}/api/vault-cid`, {
595
+ method: "POST",
596
+ headers: { "Content-Type": "application/json" },
597
+ body: JSON.stringify({
598
+ walletAddress: smartAccount,
599
+ cid,
600
+ delegationSignature: d.delegationSignature,
601
+ sessionId: d.sessionId,
602
+ expiryTimestamp: d.expiryTimestamp
603
+ })
604
+ });
605
+ if (!res.ok) throw new Error(`keyed migration: SA copy failed (${res.status})`);
606
+ }
607
+ async function markMoved(env, owner, smartAccount) {
608
+ const d = await delegation(env);
609
+ const res = await env.fetch(`${env.apiBase}/api/vault-cid/move`, {
610
+ method: "POST",
611
+ headers: { "Content-Type": "application/json" },
612
+ body: JSON.stringify({
613
+ walletAddress: owner,
614
+ targetSmartAccount: smartAccount,
615
+ delegationSignature: d.delegationSignature,
616
+ sessionId: d.sessionId,
617
+ expiryTimestamp: d.expiryTimestamp
618
+ })
619
+ });
620
+ if (!res.ok) throw new Error(`keyed migration: move failed (${res.status})`);
621
+ }
622
+ async function reconcileAfterMove(env, owner, smartAccount) {
623
+ const frozen = await readPointer(env, owner);
624
+ if (!frozen.cid) throw new Error("keyed migration: legacy pointer empty after the move");
625
+ const copied = await readPointer(env, smartAccount);
626
+ if (copied.cid === frozen.cid) return;
627
+ await copyPointer(env, smartAccount, frozen.cid);
628
+ const check = await readPointer(env, smartAccount);
629
+ if (check.cid !== frozen.cid) throw new Error("keyed migration: SA copy differs after the move");
630
+ }
631
+ async function migrateKeyedPointer(env) {
632
+ const owner = env.ownerAddress.toLowerCase();
633
+ const smartAccount = env.smartAccount.toLowerCase();
634
+ const legacy = await readPointer(env, owner);
635
+ if (legacy.moved) {
636
+ if ((legacy.movedTo ?? "").toLowerCase() !== smartAccount) {
637
+ throw new Error("keyed migration: legacy pointer moved to another smart account");
638
+ }
639
+ await reconcileAfterMove(env, owner, smartAccount);
640
+ return "already_moved";
641
+ }
642
+ if (!legacy.cid) return "no_pointer";
643
+ const target = await readPointer(env, smartAccount);
644
+ if (target.cid !== null && target.cid !== legacy.cid) return "conflict";
645
+ if (target.cid === null) await copyPointer(env, smartAccount, legacy.cid);
646
+ await markMoved(env, owner, smartAccount);
647
+ await reconcileAfterMove(env, owner, smartAccount);
648
+ return "moved";
649
+ }
601
650
  export {
602
- CID_REGISTRY_ABI,
651
+ KEYED_MIGRATION_ENABLED,
652
+ PASSAGE_ENABLED,
653
+ canWritePointer,
603
654
  clearIdentity,
604
655
  clearSmartAccountCache,
605
656
  computeSmartAccountAddress,
657
+ createPassageIO,
606
658
  createVaultSmartAccount,
607
- flushCidOnChainSync,
659
+ deriveIdentity,
608
660
  formatSecretKeyForDisplay,
609
661
  generateSecretKey,
610
662
  getCachedSmartAccountAddress,
@@ -614,22 +666,22 @@ export {
614
666
  getIdentityOwner,
615
667
  getIdentitySmartAccount,
616
668
  getIdentitySnapshot,
617
- getOnChainSyncStatus,
618
669
  getOwnerFromPassword,
619
670
  getPimlicoApiKey,
620
671
  getTargetChain,
672
+ identityState,
621
673
  initIdentityFromPassword,
622
674
  initIdentityFromSigner,
623
- isCidRegistryConfigured,
624
675
  isIdentityConnected,
625
676
  isSmartAccountConfigured,
626
677
  isValidSecretKey,
678
+ migrateKeyedPointer,
627
679
  parseSecretKeyInput,
628
- publishCidOnChain,
629
- readCidOnChain,
630
- resetOnChainSync,
631
- scheduleCidOnChainSync,
680
+ readPassageState,
681
+ runPassage,
682
+ runPassageWith,
632
683
  signMessageWithIdentity,
633
684
  subscribeIdentity,
634
- useIdentity
685
+ useIdentity,
686
+ verifyAAAuth
635
687
  };