@cavos/kit 0.0.3 → 0.0.4

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.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AuthProvider, I as Identity, W as WalletRegistry, R as RegisteredWallet, D as DevicePublicKey, a as RecoveryClient, P as PendingDeviceRequest, b as DeviceSigner, c as DeviceSignature, C as ChainAdapter, d as ComputeAddressParams, e as ChainCall, f as PasskeyAssertion, S as StellarNetwork } from './Cavos-BH2_tOQ2.mjs';
2
- export { g as Cavos, h as CavosSolana, i as CavosStellar, j as CavosWallet, k as Chain, l as ConnectOptions, m as ConnectSolanaOptions, n as ConnectStatus, o as ConnectStellarOptions, p as DEVICE_ACCOUNT_PROGRAM_ID, q as DEVICE_ACCOUNT_WASM_HASH, E as EnrolledPasskey, F as FACTORY_CONTRACT_ID, r as InMemoryWalletRegistry, s as InstructionAccount, t as InstructionData, N as NATIVE_SAC_ID, u as NetworkEnv, v as PasskeyApprovable, w as PasskeyEnrollParams, x as PasskeySigner, y as PasskeySignerOptions, z as RecoverSolanaOptions, B as RecoverStellarOptions, G as RecoveryOptions, H as SECP256R1_PROGRAM_ID, J as SOLANA_NETWORKS, K as STELLAR_NETWORKS, L as SolanaAdapter, M as SolanaAdapterOptions, O as SolanaNetwork, Q as SolanaRelayer, T as SolanaRelayerOptions, U as StaticIdentity, V as StellarRelayer, X as StellarRelayerOptions, Y as anchorDiscriminator, Z as approveDeviceEverywhere, _ as base64urlEncode, $ as batchChallenge, a0 as buildSecp256r1Instruction, a1 as compressedPubkey, a2 as encodeLowSSignature, a3 as lowS, a4 as recoverCandidatePublicKeys, a5 as serializeInstructions, a6 as webauthnDigest } from './Cavos-BH2_tOQ2.mjs';
1
+ import { A as AuthProvider, I as Identity, W as WalletRegistry, R as RegisteredWallet, D as DevicePublicKey, a as RecoveryClient, P as PendingDeviceRequest, b as DeviceSigner, c as DeviceSignature, C as ChainAdapter, d as ComputeAddressParams, e as ChainCall, f as PasskeyAssertion, S as StellarNetwork } from './Cavos-x9qFpOvJ.mjs';
2
+ export { g as Cavos, h as CavosSolana, i as CavosStellar, j as CavosWallet, k as Chain, l as ConnectOptions, m as ConnectSolanaOptions, n as ConnectStatus, o as ConnectStellarOptions, p as DEVICE_ACCOUNT_PROGRAM_ID, q as DEVICE_ACCOUNT_WASM_HASH, E as EnrolledPasskey, F as FACTORY_CONTRACT_ID, r as InMemoryWalletRegistry, s as InstructionAccount, t as InstructionData, N as NATIVE_SAC_ID, u as NetworkEnv, v as PasskeyApprovable, w as PasskeyEnrollParams, x as PasskeySigner, y as PasskeySignerOptions, z as RecoverSolanaOptions, B as RecoverStellarOptions, G as RecoveryOptions, H as SECP256R1_PROGRAM_ID, J as SOLANA_NETWORKS, K as STELLAR_NETWORKS, L as SolanaAdapter, M as SolanaAdapterOptions, O as SolanaNetwork, Q as SolanaRelayer, T as SolanaRelayerOptions, U as StaticIdentity, V as StellarRelayer, X as StellarRelayerOptions, Y as anchorDiscriminator, Z as approveDeviceEverywhere, _ as base64urlEncode, $ as batchChallenge, a0 as buildSecp256r1Instruction, a1 as compressedPubkey, a2 as encodeLowSSignature, a3 as lowS, a4 as recoverCandidatePublicKeys, a5 as serializeInstructions, a6 as webauthnDigest } from './Cavos-x9qFpOvJ.mjs';
3
3
  import { Signer, ArraySignatureType } from 'starknet';
4
4
  import { rpc, xdr } from '@stellar/stellar-sdk';
5
5
  import '@solana/web3.js';
@@ -260,6 +260,9 @@ declare class StarknetAdapter implements ChainAdapter {
260
260
  buildAddApprover(accountAddress: string, passkey: DevicePublicKey): ChainCall;
261
261
  buildRemoveApprover(accountAddress: string, passkey: DevicePublicKey): ChainCall;
262
262
  isApprover(accountAddress: string, passkey: DevicePublicKey): Promise<boolean>;
263
+ /** True if the account has at least one passkey registered as an approver.
264
+ * Lets the UI decide whether to offer passkey approval before prompting. */
265
+ hasPasskeyApprover(accountAddress: string): Promise<boolean>;
263
266
  getPasskeyNonce(accountAddress: string): Promise<bigint>;
264
267
  /** This chain's leaf for approving `add_signer(newSigner)` at `nonce`:
265
268
  * `sha256(new_x || new_y || nonce)` (coords 32B BE, nonce 16B BE). The batch
@@ -376,6 +379,9 @@ declare class StellarAdapter {
376
379
  * `leaves`/`leafIndex` place this chain's leaf in the multi-chain batch. */
377
380
  buildAddSignerViaPasskey(accountAddress: string, newSigner: DevicePublicKey, passkey: DevicePublicKey, nonce: bigint, leaves: Uint8Array[], leafIndex: number, assertion: PasskeyAssertion): xdr.HostFunction;
378
381
  /** Read whether `passkey` is a registered approver (read-only simulation). */
382
+ /** True if the account has at least one passkey registered as an approver.
383
+ * Reads the contract's `approvers` view and checks the list is non-empty. */
384
+ hasPasskeyApprover(accountAddress: string, readSource: string): Promise<boolean>;
379
385
  isApprover(accountAddress: string, passkey: DevicePublicKey, readSource: string): Promise<boolean>;
380
386
  /** Read the current passkey-approval nonce (read-only simulation). */
381
387
  passkeyNonce(accountAddress: string, readSource: string): Promise<bigint>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AuthProvider, I as Identity, W as WalletRegistry, R as RegisteredWallet, D as DevicePublicKey, a as RecoveryClient, P as PendingDeviceRequest, b as DeviceSigner, c as DeviceSignature, C as ChainAdapter, d as ComputeAddressParams, e as ChainCall, f as PasskeyAssertion, S as StellarNetwork } from './Cavos-BH2_tOQ2.js';
2
- export { g as Cavos, h as CavosSolana, i as CavosStellar, j as CavosWallet, k as Chain, l as ConnectOptions, m as ConnectSolanaOptions, n as ConnectStatus, o as ConnectStellarOptions, p as DEVICE_ACCOUNT_PROGRAM_ID, q as DEVICE_ACCOUNT_WASM_HASH, E as EnrolledPasskey, F as FACTORY_CONTRACT_ID, r as InMemoryWalletRegistry, s as InstructionAccount, t as InstructionData, N as NATIVE_SAC_ID, u as NetworkEnv, v as PasskeyApprovable, w as PasskeyEnrollParams, x as PasskeySigner, y as PasskeySignerOptions, z as RecoverSolanaOptions, B as RecoverStellarOptions, G as RecoveryOptions, H as SECP256R1_PROGRAM_ID, J as SOLANA_NETWORKS, K as STELLAR_NETWORKS, L as SolanaAdapter, M as SolanaAdapterOptions, O as SolanaNetwork, Q as SolanaRelayer, T as SolanaRelayerOptions, U as StaticIdentity, V as StellarRelayer, X as StellarRelayerOptions, Y as anchorDiscriminator, Z as approveDeviceEverywhere, _ as base64urlEncode, $ as batchChallenge, a0 as buildSecp256r1Instruction, a1 as compressedPubkey, a2 as encodeLowSSignature, a3 as lowS, a4 as recoverCandidatePublicKeys, a5 as serializeInstructions, a6 as webauthnDigest } from './Cavos-BH2_tOQ2.js';
1
+ import { A as AuthProvider, I as Identity, W as WalletRegistry, R as RegisteredWallet, D as DevicePublicKey, a as RecoveryClient, P as PendingDeviceRequest, b as DeviceSigner, c as DeviceSignature, C as ChainAdapter, d as ComputeAddressParams, e as ChainCall, f as PasskeyAssertion, S as StellarNetwork } from './Cavos-x9qFpOvJ.js';
2
+ export { g as Cavos, h as CavosSolana, i as CavosStellar, j as CavosWallet, k as Chain, l as ConnectOptions, m as ConnectSolanaOptions, n as ConnectStatus, o as ConnectStellarOptions, p as DEVICE_ACCOUNT_PROGRAM_ID, q as DEVICE_ACCOUNT_WASM_HASH, E as EnrolledPasskey, F as FACTORY_CONTRACT_ID, r as InMemoryWalletRegistry, s as InstructionAccount, t as InstructionData, N as NATIVE_SAC_ID, u as NetworkEnv, v as PasskeyApprovable, w as PasskeyEnrollParams, x as PasskeySigner, y as PasskeySignerOptions, z as RecoverSolanaOptions, B as RecoverStellarOptions, G as RecoveryOptions, H as SECP256R1_PROGRAM_ID, J as SOLANA_NETWORKS, K as STELLAR_NETWORKS, L as SolanaAdapter, M as SolanaAdapterOptions, O as SolanaNetwork, Q as SolanaRelayer, T as SolanaRelayerOptions, U as StaticIdentity, V as StellarRelayer, X as StellarRelayerOptions, Y as anchorDiscriminator, Z as approveDeviceEverywhere, _ as base64urlEncode, $ as batchChallenge, a0 as buildSecp256r1Instruction, a1 as compressedPubkey, a2 as encodeLowSSignature, a3 as lowS, a4 as recoverCandidatePublicKeys, a5 as serializeInstructions, a6 as webauthnDigest } from './Cavos-x9qFpOvJ.js';
3
3
  import { Signer, ArraySignatureType } from 'starknet';
4
4
  import { rpc, xdr } from '@stellar/stellar-sdk';
5
5
  import '@solana/web3.js';
@@ -260,6 +260,9 @@ declare class StarknetAdapter implements ChainAdapter {
260
260
  buildAddApprover(accountAddress: string, passkey: DevicePublicKey): ChainCall;
261
261
  buildRemoveApprover(accountAddress: string, passkey: DevicePublicKey): ChainCall;
262
262
  isApprover(accountAddress: string, passkey: DevicePublicKey): Promise<boolean>;
263
+ /** True if the account has at least one passkey registered as an approver.
264
+ * Lets the UI decide whether to offer passkey approval before prompting. */
265
+ hasPasskeyApprover(accountAddress: string): Promise<boolean>;
263
266
  getPasskeyNonce(accountAddress: string): Promise<bigint>;
264
267
  /** This chain's leaf for approving `add_signer(newSigner)` at `nonce`:
265
268
  * `sha256(new_x || new_y || nonce)` (coords 32B BE, nonce 16B BE). The batch
@@ -376,6 +379,9 @@ declare class StellarAdapter {
376
379
  * `leaves`/`leafIndex` place this chain's leaf in the multi-chain batch. */
377
380
  buildAddSignerViaPasskey(accountAddress: string, newSigner: DevicePublicKey, passkey: DevicePublicKey, nonce: bigint, leaves: Uint8Array[], leafIndex: number, assertion: PasskeyAssertion): xdr.HostFunction;
378
381
  /** Read whether `passkey` is a registered approver (read-only simulation). */
382
+ /** True if the account has at least one passkey registered as an approver.
383
+ * Reads the contract's `approvers` view and checks the list is non-empty. */
384
+ hasPasskeyApprover(accountAddress: string, readSource: string): Promise<boolean>;
379
385
  isApprover(accountAddress: string, passkey: DevicePublicKey, readSource: string): Promise<boolean>;
380
386
  /** Read the current passkey-approval nonce (read-only simulation). */
381
387
  passkeyNonce(accountAddress: string, readSource: string): Promise<bigint>;
package/dist/index.js CHANGED
@@ -262,6 +262,17 @@ var StarknetAdapter = class {
262
262
  });
263
263
  return BigInt(res[0] ?? 0) !== 0n;
264
264
  }
265
+ /** True if the account has at least one passkey registered as an approver.
266
+ * Lets the UI decide whether to offer passkey approval before prompting. */
267
+ async hasPasskeyApprover(accountAddress) {
268
+ if (!this.opts.provider) throw new Error("kit/starknet: provider required for reads");
269
+ const res = await this.opts.provider.callContract({
270
+ contractAddress: accountAddress,
271
+ entrypoint: "get_approver_count",
272
+ calldata: []
273
+ });
274
+ return BigInt(res[0] ?? 0) > 0n;
275
+ }
265
276
  async getPasskeyNonce(accountAddress) {
266
277
  if (!this.opts.provider) throw new Error("kit/starknet: provider required for reads");
267
278
  const res = await this.opts.provider.callContract({
@@ -600,6 +611,11 @@ var SolanaAdapter = class {
600
611
  return [precompileIx, ix];
601
612
  }
602
613
  /** Read whether `passkey` is a registered approver. */
614
+ /** True if the account has at least one passkey registered as an approver. */
615
+ async hasPasskeyApprover(account) {
616
+ const approvers = await this.fetchApprovers(new web3_js.PublicKey(account));
617
+ return approvers.length > 0;
618
+ }
603
619
  async isApprover(account, passkey) {
604
620
  const approvers = await this.fetchApprovers(new web3_js.PublicKey(account));
605
621
  const target = Buffer.from(compressedPubkey(passkey)).toString("hex");
@@ -1292,6 +1308,8 @@ var CavosSolana = class _CavosSolana {
1292
1308
  this.feePayer = feePayer;
1293
1309
  /** Discriminant for the `CavosWallet` union — narrows `execute()` per chain. */
1294
1310
  this.chain = "solana";
1311
+ /** True when this connect just created a brand-new account (first sign-up). */
1312
+ this.isNewAccount = false;
1295
1313
  }
1296
1314
  get publicKey() {
1297
1315
  return this.devicePubkey;
@@ -1342,7 +1360,7 @@ var CavosSolana = class _CavosSolana {
1342
1360
  }
1343
1361
  await registry.register({ userId: identity.userId, address, initialSigner: devicePubkey });
1344
1362
  const isSigner = await adapter.isAuthorizedSigner(address, devicePubkey);
1345
- return new _CavosSolana(
1363
+ const wallet = new _CavosSolana(
1346
1364
  identity,
1347
1365
  address,
1348
1366
  isSigner ? "ready" : "needs-device-approval",
@@ -1352,6 +1370,8 @@ var CavosSolana = class _CavosSolana {
1352
1370
  relayer,
1353
1371
  opts.feePayer
1354
1372
  );
1373
+ wallet.isNewAccount = !deployed && isSigner;
1374
+ return wallet;
1355
1375
  }
1356
1376
  /** Authorize an additional device signer (device-signed via precompile). */
1357
1377
  async addSigner(pubkey) {
@@ -1378,6 +1398,16 @@ var CavosSolana = class _CavosSolana {
1378
1398
  const transactionHash = await this.send(ixs);
1379
1399
  return { transactionHash };
1380
1400
  }
1401
+ /** True if this account already has a passkey enrolled as an approver, so a
1402
+ * new device can be approved with the passkey instead of the email flow. */
1403
+ async hasPasskey() {
1404
+ return this.adapter.hasPasskeyApprover(this.address);
1405
+ }
1406
+ /** Re-read (from chain) whether THIS device is now an authorized signer.
1407
+ * Used to poll for readiness after a passkey approval before it's indexed. */
1408
+ async isReady() {
1409
+ return this.adapter.isAuthorizedSigner(this.address, this.devicePubkey);
1410
+ }
1381
1411
  /**
1382
1412
  * From a fresh browser (status `needs-device-approval`), approve adding THIS
1383
1413
  * device with the user's synced passkey. Gasless via the relayer — the bundle
@@ -1669,6 +1699,25 @@ var StellarAdapter = class {
1669
1699
  ]);
1670
1700
  }
1671
1701
  /** Read whether `passkey` is a registered approver (read-only simulation). */
1702
+ /** True if the account has at least one passkey registered as an approver.
1703
+ * Reads the contract's `approvers` view and checks the list is non-empty. */
1704
+ async hasPasskeyApprover(accountAddress, readSource) {
1705
+ if (!await this.isDeployed(accountAddress)) return false;
1706
+ const { Account: Account3, TransactionBuilder: TransactionBuilder2, BASE_FEE: BASE_FEE2 } = await import('@stellar/stellar-sdk');
1707
+ const src = new Account3(readSource, "0");
1708
+ const op = stellarSdk.Operation.invokeHostFunction({
1709
+ func: invokeFunc(accountAddress, "approvers", []),
1710
+ auth: []
1711
+ });
1712
+ const tx2 = new TransactionBuilder2(src, { fee: BASE_FEE2, networkPassphrase: this.passphrase }).addOperation(op).setTimeout(30).build();
1713
+ const sim = await this.server().simulateTransaction(tx2);
1714
+ if (stellarSdk.rpc.Api.isSimulationError(sim)) {
1715
+ throw new Error(`kit/stellar: approvers simulation failed: ${sim.error}`);
1716
+ }
1717
+ if (!sim.result?.retval) return false;
1718
+ const list = stellarSdk.scValToNative(sim.result.retval);
1719
+ return Array.isArray(list) && list.length > 0;
1720
+ }
1672
1721
  async isApprover(accountAddress, passkey, readSource) {
1673
1722
  if (!await this.isDeployed(accountAddress)) return false;
1674
1723
  const { Account: Account3, TransactionBuilder: TransactionBuilder2, BASE_FEE: BASE_FEE2 } = await import('@stellar/stellar-sdk');
@@ -1873,6 +1922,8 @@ var CavosStellar = class _CavosStellar {
1873
1922
  this.sourceKeypair = sourceKeypair;
1874
1923
  /** Discriminant for the `CavosWallet` union — narrows `execute()` per chain. */
1875
1924
  this.chain = "stellar";
1925
+ /** True when this connect just created a brand-new account (first sign-up). */
1926
+ this.isNewAccount = false;
1876
1927
  }
1877
1928
  get publicKey() {
1878
1929
  return this.devicePubkey;
@@ -1901,13 +1952,16 @@ var CavosStellar = class _CavosStellar {
1901
1952
  return build(existing.address, isSigner2 ? "ready" : "needs-device-approval");
1902
1953
  }
1903
1954
  const address = adapter.computeAddress(addressSeed, devicePubkey);
1904
- if (!await adapter.isDeployed(address)) {
1955
+ const wasDeployed = await adapter.isDeployed(address);
1956
+ if (!wasDeployed) {
1905
1957
  const func = adapter.buildDeploy(addressSeed, devicePubkey);
1906
1958
  await self.submitHostFunction(func, void 0);
1907
1959
  }
1908
1960
  await registry.register({ userId: identity.userId, address, initialSigner: devicePubkey });
1909
1961
  const isSigner = await adapter.isAuthorizedSigner(address, devicePubkey, readSource);
1910
- return build(address, isSigner ? "ready" : "needs-device-approval");
1962
+ const wallet = build(address, isSigner ? "ready" : "needs-device-approval");
1963
+ wallet.isNewAccount = !wasDeployed && isSigner;
1964
+ return wallet;
1911
1965
  }
1912
1966
  /** Authorize an additional device signer (device-signed via `__check_auth`). */
1913
1967
  async addSigner(pubkey) {
@@ -1935,6 +1989,18 @@ var CavosStellar = class _CavosStellar {
1935
1989
  const transactionHash = await this.submitHostFunction(func, this.address);
1936
1990
  return { transactionHash };
1937
1991
  }
1992
+ /** True if this account already has a passkey enrolled as an approver, so a
1993
+ * new device can be approved with the passkey instead of the email flow. */
1994
+ async hasPasskey() {
1995
+ const readSource = await this.resolveSource();
1996
+ return this.adapter.hasPasskeyApprover(this.address, readSource);
1997
+ }
1998
+ /** Re-read (from chain) whether THIS device is now an authorized signer.
1999
+ * Used to poll for readiness after a passkey approval before it's indexed. */
2000
+ async isReady() {
2001
+ const readSource = await this.resolveSource();
2002
+ return this.adapter.isAuthorizedSigner(this.address, this.devicePubkey, readSource);
2003
+ }
1938
2004
  /**
1939
2005
  * From a fresh browser (status `needs-device-approval`), approve adding THIS
1940
2006
  * device using the user's synced passkey. Gasless via the relayer — the call
@@ -2244,6 +2310,9 @@ var Cavos = class _Cavos {
2244
2310
  this.chain = "starknet";
2245
2311
  /** Request id of the pending device-addition, when status is needs-device-approval. */
2246
2312
  this.pendingRequestId = null;
2313
+ /** True when this connect just created & deployed a brand-new account (first
2314
+ * sign-up), so the UI can offer a one-time "secure your account" step. */
2315
+ this.isNewAccount = false;
2247
2316
  }
2248
2317
  /**
2249
2318
  * Unified entry point. Pick a `chain` and an `network` environment; the kit
@@ -2339,7 +2408,7 @@ var Cavos = class _Cavos {
2339
2408
  if (existing) {
2340
2409
  const account2 = makeAccount(existing.address);
2341
2410
  const isSigner2 = await adapter.isAuthorizedSigner(existing.address, devicePubkey);
2342
- const cavos = new _Cavos(
2411
+ const cavos2 = new _Cavos(
2343
2412
  identity,
2344
2413
  existing.address,
2345
2414
  isSigner2 ? "ready" : "needs-device-approval",
@@ -2353,7 +2422,7 @@ var Cavos = class _Cavos {
2353
2422
  const fresh = dedup && Date.now() - dedup.requestedAt < DEVICE_REQUEST_DEDUP_MS;
2354
2423
  try {
2355
2424
  if (fresh) {
2356
- cavos.pendingRequestId = dedup.requestId;
2425
+ cavos2.pendingRequestId = dedup.requestId;
2357
2426
  } else {
2358
2427
  const { requestId } = await recovery.requestDeviceAddition({
2359
2428
  userId: identity.userId,
@@ -2361,14 +2430,14 @@ var Cavos = class _Cavos {
2361
2430
  newSigner: devicePubkey,
2362
2431
  ...identity.email ? { email: identity.email } : {}
2363
2432
  });
2364
- cavos.pendingRequestId = requestId;
2433
+ cavos2.pendingRequestId = requestId;
2365
2434
  lastDeviceRequest.set(identity.userId, { requestId, requestedAt: Date.now() });
2366
2435
  }
2367
2436
  } catch (e) {
2368
2437
  console.warn("[Cavos] requestDeviceAddition failed:", e);
2369
2438
  }
2370
2439
  }
2371
- return cavos;
2440
+ return cavos2;
2372
2441
  }
2373
2442
  const address = adapter.computeAddress({ addressSeed, initialSigner: devicePubkey });
2374
2443
  const account = makeAccount(address);
@@ -2399,7 +2468,7 @@ var Cavos = class _Cavos {
2399
2468
  console.warn("[Cavos] isAuthorizedSigner read failed:", e);
2400
2469
  isSigner = !alreadyDeployed;
2401
2470
  }
2402
- return new _Cavos(
2471
+ const cavos = new _Cavos(
2403
2472
  identity,
2404
2473
  address,
2405
2474
  isSigner ? "ready" : "needs-device-approval",
@@ -2408,6 +2477,8 @@ var Cavos = class _Cavos {
2408
2477
  devicePubkey,
2409
2478
  paymasterConfig
2410
2479
  );
2480
+ cavos.isNewAccount = !alreadyDeployed && isSigner;
2481
+ return cavos;
2411
2482
  }
2412
2483
  /** This device's public key (e.g. to request addition to an existing wallet). */
2413
2484
  get publicKey() {
@@ -2453,8 +2524,24 @@ var Cavos = class _Cavos {
2453
2524
  const { transactionHash } = await this.execute([
2454
2525
  this.adapter.buildAddApprover(this.address, pubkey)
2455
2526
  ]);
2527
+ try {
2528
+ await this.account.waitForTransaction(transactionHash);
2529
+ } catch (e) {
2530
+ console.warn("[Cavos] add_approver receipt wait failed:", e);
2531
+ }
2456
2532
  return { transactionHash };
2457
2533
  }
2534
+ /** True if this account already has a passkey enrolled as an approver, so a
2535
+ * new device can be approved with the passkey instead of the email flow. */
2536
+ async hasPasskey() {
2537
+ return this.adapter.hasPasskeyApprover(this.address);
2538
+ }
2539
+ /** Re-read (from chain) whether THIS device is now an authorized signer.
2540
+ * Cheap and side-effect free — used to poll for readiness after a passkey /
2541
+ * device approval submits, before the new signer is indexed. */
2542
+ async isReady() {
2543
+ return this.adapter.isAuthorizedSigner(this.address, this.devicePubkey);
2544
+ }
2458
2545
  /**
2459
2546
  * From a brand-new browser (status `needs-device-approval`), use the user's
2460
2547
  * synced passkey to authorize adding THIS device — no trip back to an already-
@@ -2606,17 +2693,15 @@ async function approveDeviceEverywhere(wallets, passkey) {
2606
2693
  const infos = await Promise.all(targets.map((w) => w.passkeyLeafForThisDevice()));
2607
2694
  const leaves = infos.map((i) => i.leaf);
2608
2695
  const assertion = await passkey.assert(batchChallenge(leaves));
2609
- const out = [];
2610
- for (let i = 0; i < targets.length; i++) {
2611
- const { transactionHash } = await targets[i].submitPasskeyApproval(
2612
- assertion,
2613
- leaves,
2614
- i,
2615
- infos[i].nonce
2616
- );
2617
- out.push({ chain: targets[i].chain, transactionHash });
2618
- }
2619
- return out;
2696
+ const settled = await Promise.allSettled(
2697
+ targets.map((w, i) => w.submitPasskeyApproval(assertion, leaves, i, infos[i].nonce))
2698
+ );
2699
+ return settled.map(
2700
+ (r, i) => r.status === "fulfilled" ? { chain: targets[i].chain, transactionHash: r.value.transactionHash } : {
2701
+ chain: targets[i].chain,
2702
+ error: r.reason instanceof Error ? r.reason.message : String(r.reason)
2703
+ }
2704
+ );
2620
2705
  }
2621
2706
  async function paymasterExecuteDirect(paymaster, userAddress, call) {
2622
2707
  const body = {