@kingdomchain/wallet-client 0.6.3 → 0.8.1

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.js CHANGED
@@ -1940,6 +1940,7 @@ var EMBEDDED_WALLET_VAULT_VERSION = 1;
1940
1940
  var EMBEDDED_WALLET_KDF_PRF = "webauthn-prf";
1941
1941
  var EMBEDDED_WALLET_KDF_PBKDF2 = "pbkdf2-passkey";
1942
1942
  var EMBEDDED_WALLET_KDF_PIN = "pbkdf2-pin";
1943
+ var EMBEDDED_WALLET_KDF_DEVICE_PIN = "device-pin";
1943
1944
  var EMBEDDED_WALLET_KEY_HD_DERIVED = "hd-derived";
1944
1945
  var EMBEDDED_WALLET_KEY_DIRECT_ENTROPY = "direct-entropy";
1945
1946
  var EMBEDDED_WALLET_RECOVERY_PHRASE_GENERAL_WARNING = {
@@ -1994,6 +1995,23 @@ var EmbeddedWalletWeakPasscodeError = class extends Error {
1994
1995
  this.reason = reason;
1995
1996
  }
1996
1997
  };
1998
+ var EmbeddedWalletPasskeyUnsupportedError = class extends EmbeddedWalletVaultError {
1999
+ code = "passkey_prf_unsupported";
2000
+ constructor(message = "This device cannot protect the wallet with a passkey; keep using the passcode") {
2001
+ super(message);
2002
+ this.name = "EmbeddedWalletPasskeyUnsupportedError";
2003
+ }
2004
+ };
2005
+ var EmbeddedWalletQuickUnlockError = class extends Error {
2006
+ code;
2007
+ attemptsLeft;
2008
+ constructor(code, message, attemptsLeft) {
2009
+ super(message);
2010
+ this.name = "EmbeddedWalletQuickUnlockError";
2011
+ this.code = code;
2012
+ this.attemptsLeft = attemptsLeft;
2013
+ }
2014
+ };
1997
2015
  var DEFAULT_HD_PATH = "m/44'/118'/0'/0/0";
1998
2016
  async function embeddedPlaintextToSigner(plaintext, prefix = BECH32_PREFIX) {
1999
2017
  if (plaintext.privateKey.length !== 32) {
@@ -2321,6 +2339,30 @@ function assertVaultPermitsTransaction(vault) {
2321
2339
  throw new EmbeddedWalletBackupRequiredError();
2322
2340
  }
2323
2341
  }
2342
+ async function encryptPlaintextWithKek(payload, kek) {
2343
+ const iv = crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES));
2344
+ const aesKey = await importAesKey(kek);
2345
+ const ciphertext = await crypto.subtle.encrypt(
2346
+ { name: "AES-GCM", iv },
2347
+ aesKey,
2348
+ new Uint8Array(serializePlaintext(payload))
2349
+ );
2350
+ return { iv: toBase64(iv), ciphertext: toBase64(new Uint8Array(ciphertext)) };
2351
+ }
2352
+ async function decryptPlaintextWithKek(iv, ciphertext, kek) {
2353
+ const aesKey = await importAesKey(kek);
2354
+ let plaintextBytes;
2355
+ try {
2356
+ plaintextBytes = await crypto.subtle.decrypt(
2357
+ { name: "AES-GCM", iv: new Uint8Array(fromBase64(iv)) },
2358
+ aesKey,
2359
+ new Uint8Array(fromBase64(ciphertext))
2360
+ );
2361
+ } catch (err) {
2362
+ throw new EmbeddedWalletDecryptError(err);
2363
+ }
2364
+ return deserializePlaintext(new Uint8Array(plaintextBytes));
2365
+ }
2324
2366
 
2325
2367
  // src/embeddedWallet/prf.ts
2326
2368
  function detectWebAuthnPrfCapabilities() {
@@ -2331,15 +2373,6 @@ function detectWebAuthnPrfCapabilities() {
2331
2373
  prfFallbackReason: "WebAuthn is not available in this environment"
2332
2374
  };
2333
2375
  }
2334
- const ua = typeof navigator !== "undefined" ? navigator.userAgent : "";
2335
- const isSafari = /Safari/i.test(ua) && !/Chrome|Chromium|CriOS|FxiOS/i.test(ua);
2336
- if (isSafari) {
2337
- return {
2338
- webAuthnAvailable: true,
2339
- prfLikelySupported: false,
2340
- prfFallbackReason: "Safari does not support WebAuthn PRF for cross-device QR flows; use PBKDF2 fallback"
2341
- };
2342
- }
2343
2376
  const getCaps = PublicKeyCredential.getClientCapabilities;
2344
2377
  if (typeof getCaps !== "function") {
2345
2378
  return {
@@ -2370,6 +2403,11 @@ function selectEmbeddedWalletKdf(caps, prfOutput) {
2370
2403
 
2371
2404
  // src/embeddedWallet/backup.ts
2372
2405
  function exportEncryptedBackup(vault) {
2406
+ if (vault.kdf === "device-pin") {
2407
+ throw new Error(
2408
+ "A PIN wallet is bound to this device and has no backup file; its backup is the 24-word recovery phrase"
2409
+ );
2410
+ }
2373
2411
  return {
2374
2412
  format: "kingdom-os-embedded-wallet-backup",
2375
2413
  version: EMBEDDED_WALLET_VAULT_VERSION,
@@ -2519,10 +2557,11 @@ function decodeCredentialId(encoded) {
2519
2557
 
2520
2558
  // src/embeddedWallet/storage.ts
2521
2559
  var DB_NAME = "kingdom-os-wallet";
2522
- var DB_VERSION = 3;
2560
+ var DB_VERSION = 4;
2523
2561
  var VAULT_STORE_NAME = "vault";
2524
2562
  var LOCKOUT_STORE_NAME = "passcode-lockout";
2525
2563
  var SESSION_STORE_NAME = "session-cache";
2564
+ var QUICK_UNLOCK_STORE_NAME = "quick-unlock";
2526
2565
  var VAULT_LEGACY_KEY = "primary";
2527
2566
  function resolveVaultStorageKey(scopeId) {
2528
2567
  const trimmed = scopeId?.trim();
@@ -2543,6 +2582,9 @@ function openDb() {
2543
2582
  if (!db.objectStoreNames.contains(SESSION_STORE_NAME)) {
2544
2583
  db.createObjectStore(SESSION_STORE_NAME);
2545
2584
  }
2585
+ if (!db.objectStoreNames.contains(QUICK_UNLOCK_STORE_NAME)) {
2586
+ db.createObjectStore(QUICK_UNLOCK_STORE_NAME);
2587
+ }
2546
2588
  };
2547
2589
  request.onsuccess = () => resolve(request.result);
2548
2590
  });
@@ -2651,6 +2693,40 @@ async function clearSessionCacheRecord(options = {}) {
2651
2693
  });
2652
2694
  db.close();
2653
2695
  }
2696
+ async function saveQuickUnlockRecord(record, options = {}) {
2697
+ const key = resolveVaultStorageKey(options.scopeId);
2698
+ const db = await openDb();
2699
+ await new Promise((resolve, reject) => {
2700
+ const tx = db.transaction(QUICK_UNLOCK_STORE_NAME, "readwrite");
2701
+ tx.objectStore(QUICK_UNLOCK_STORE_NAME).put(record, key);
2702
+ tx.oncomplete = () => resolve();
2703
+ tx.onerror = () => reject(tx.error ?? new Error("IndexedDB write failed"));
2704
+ });
2705
+ db.close();
2706
+ }
2707
+ async function loadQuickUnlockRecord(options = {}) {
2708
+ const key = resolveVaultStorageKey(options.scopeId);
2709
+ const db = await openDb();
2710
+ const record = await new Promise((resolve, reject) => {
2711
+ const tx = db.transaction(QUICK_UNLOCK_STORE_NAME, "readonly");
2712
+ const request = tx.objectStore(QUICK_UNLOCK_STORE_NAME).get(key);
2713
+ request.onsuccess = () => resolve(request.result ?? null);
2714
+ request.onerror = () => reject(request.error ?? new Error("IndexedDB read failed"));
2715
+ });
2716
+ db.close();
2717
+ return record;
2718
+ }
2719
+ async function clearQuickUnlockRecord(options = {}) {
2720
+ const key = resolveVaultStorageKey(options.scopeId);
2721
+ const db = await openDb();
2722
+ await new Promise((resolve, reject) => {
2723
+ const tx = db.transaction(QUICK_UNLOCK_STORE_NAME, "readwrite");
2724
+ tx.objectStore(QUICK_UNLOCK_STORE_NAME).delete(key);
2725
+ tx.oncomplete = () => resolve();
2726
+ tx.onerror = () => reject(tx.error ?? new Error("IndexedDB delete failed"));
2727
+ });
2728
+ db.close();
2729
+ }
2654
2730
  var EMBEDDED_WALLET_SESSION_TTL_MS = 12 * 60 * 60 * 1e3;
2655
2731
  var AES_GCM_IV_BYTES2 = 12;
2656
2732
  function serializeSessionPlaintext(plaintext) {
@@ -2890,10 +2966,264 @@ function assertPasscodeAllowedForCreation(passcode) {
2890
2966
  throw new EmbeddedWalletWeakPasscodeError(strength.blockReason ?? "too_weak");
2891
2967
  }
2892
2968
  }
2969
+ var QUICK_UNLOCK_PIN_LENGTH = 6;
2970
+ var QUICK_UNLOCK_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
2971
+ var QUICK_UNLOCK_MAX_ATTEMPTS = 5;
2972
+ var QUICK_UNLOCK_PBKDF2_ITERATIONS = 6e5;
2973
+ var AES_GCM_IV_BYTES3 = 12;
2974
+ function assertQuickUnlockPinAllowed(pin) {
2975
+ if (typeof pin !== "string" || !new RegExp(`^\\d{${QUICK_UNLOCK_PIN_LENGTH}}$`).test(pin)) {
2976
+ throw new EmbeddedWalletQuickUnlockError(
2977
+ "invalid_pin",
2978
+ `PIN must be exactly ${QUICK_UNLOCK_PIN_LENGTH} digits`
2979
+ );
2980
+ }
2981
+ if (isTrivialPin(pin)) {
2982
+ throw new EmbeddedWalletQuickUnlockError(
2983
+ "invalid_pin",
2984
+ "PIN is too easy to guess; avoid repeats and sequences like 123456"
2985
+ );
2986
+ }
2987
+ }
2988
+ function isTrivialPin(pin) {
2989
+ const digits = pin.split("").map(Number);
2990
+ const steps = digits.slice(1).map((d, i) => d - digits[i]);
2991
+ if (steps.every((s) => s === 0)) return true;
2992
+ if (steps.every((s) => s === 1) || steps.every((s) => s === -1)) return true;
2993
+ for (const period of [2, 3]) {
2994
+ if (pin === pin.slice(0, period).repeat(pin.length / period)) return true;
2995
+ }
2996
+ return false;
2997
+ }
2998
+ async function derivePinKey(pin, salt, iterations) {
2999
+ const material = await crypto.subtle.importKey(
3000
+ "raw",
3001
+ new TextEncoder().encode(pin),
3002
+ "PBKDF2",
3003
+ false,
3004
+ ["deriveKey"]
3005
+ );
3006
+ return crypto.subtle.deriveKey(
3007
+ { name: "PBKDF2", salt: new Uint8Array(salt), iterations, hash: "SHA-256" },
3008
+ material,
3009
+ { name: "AES-GCM", length: 256 },
3010
+ false,
3011
+ ["encrypt", "decrypt"]
3012
+ );
3013
+ }
3014
+ async function createQuickUnlockRecord(options) {
3015
+ const { plaintext, publicAddress, pin, ttlMs, iterations, ...storageOptions } = options;
3016
+ assertQuickUnlockPinAllowed(pin);
3017
+ const rounds = iterations ?? QUICK_UNLOCK_PBKDF2_ITERATIONS;
3018
+ const salt = crypto.getRandomValues(new Uint8Array(32));
3019
+ const pinKey = await derivePinKey(pin, salt, rounds);
3020
+ const deviceKey = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [
3021
+ "encrypt",
3022
+ "decrypt"
3023
+ ]);
3024
+ const innerIv = crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES3));
3025
+ const inner = await crypto.subtle.encrypt(
3026
+ { name: "AES-GCM", iv: innerIv },
3027
+ pinKey,
3028
+ new Uint8Array(serializePlaintext(plaintext))
3029
+ );
3030
+ const outerIv = crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES3));
3031
+ const outer = await crypto.subtle.encrypt({ name: "AES-GCM", iv: outerIv }, deviceKey, inner);
3032
+ const record = {
3033
+ deviceKey,
3034
+ publicAddress,
3035
+ salt: toBase64(salt),
3036
+ iterations: rounds,
3037
+ innerIv: toBase64(innerIv),
3038
+ outerIv: toBase64(outerIv),
3039
+ ciphertext: toBase64(new Uint8Array(outer)),
3040
+ expiresAt: Date.now() + (ttlMs ?? QUICK_UNLOCK_TTL_MS),
3041
+ failedAttempts: 0
3042
+ };
3043
+ await saveQuickUnlockRecord(record, storageOptions);
3044
+ return record;
3045
+ }
3046
+ async function openQuickUnlockRecord(options) {
3047
+ const { pin, ...storageOptions } = options;
3048
+ if (typeof pin !== "string" || !/^\d+$/.test(pin) || pin.length !== QUICK_UNLOCK_PIN_LENGTH) {
3049
+ throw new EmbeddedWalletQuickUnlockError(
3050
+ "invalid_pin",
3051
+ `PIN must be exactly ${QUICK_UNLOCK_PIN_LENGTH} digits`
3052
+ );
3053
+ }
3054
+ const record = await loadQuickUnlockRecord(storageOptions);
3055
+ if (!record) {
3056
+ throw new EmbeddedWalletQuickUnlockError("not_set", "No PIN is set up on this device");
3057
+ }
3058
+ if (typeof record.expiresAt !== "number" || Date.now() >= record.expiresAt) {
3059
+ throw new EmbeddedWalletQuickUnlockError(
3060
+ "expired",
3061
+ "PIN expired; unlock with Face ID or your passcode"
3062
+ );
3063
+ }
3064
+ const attempt = (record.failedAttempts ?? 0) + 1;
3065
+ await saveQuickUnlockRecord({ ...record, failedAttempts: attempt }, storageOptions);
3066
+ let inner;
3067
+ try {
3068
+ inner = await crypto.subtle.decrypt(
3069
+ { name: "AES-GCM", iv: new Uint8Array(fromBase64(record.outerIv)) },
3070
+ record.deviceKey,
3071
+ new Uint8Array(fromBase64(record.ciphertext))
3072
+ );
3073
+ } catch {
3074
+ await clearQuickUnlockRecord(storageOptions).catch(() => void 0);
3075
+ throw new EmbeddedWalletQuickUnlockError("not_set", "PIN record is unusable on this device");
3076
+ }
3077
+ const pinKey = await derivePinKey(pin, fromBase64(record.salt), record.iterations);
3078
+ let plaintextBytes;
3079
+ try {
3080
+ plaintextBytes = await crypto.subtle.decrypt(
3081
+ { name: "AES-GCM", iv: new Uint8Array(fromBase64(record.innerIv)) },
3082
+ pinKey,
3083
+ inner
3084
+ );
3085
+ } catch {
3086
+ if (attempt >= QUICK_UNLOCK_MAX_ATTEMPTS) {
3087
+ await clearQuickUnlockRecord(storageOptions).catch(() => void 0);
3088
+ throw new EmbeddedWalletQuickUnlockError(
3089
+ "wiped",
3090
+ "Too many wrong PINs; unlock with Face ID or your passcode"
3091
+ );
3092
+ }
3093
+ throw new EmbeddedWalletQuickUnlockError(
3094
+ "wrong_pin",
3095
+ "Wrong PIN",
3096
+ QUICK_UNLOCK_MAX_ATTEMPTS - attempt
3097
+ );
3098
+ }
3099
+ await saveQuickUnlockRecord({ ...record, failedAttempts: 0 }, storageOptions);
3100
+ return {
3101
+ plaintext: deserializePlaintext(new Uint8Array(plaintextBytes)),
3102
+ publicAddress: record.publicAddress
3103
+ };
3104
+ }
3105
+ async function getQuickUnlockStatus(options = {}) {
3106
+ const record = await loadQuickUnlockRecord(options);
3107
+ if (!record) {
3108
+ return {
3109
+ enabled: false,
3110
+ expired: false,
3111
+ expiresAt: null,
3112
+ attemptsLeft: QUICK_UNLOCK_MAX_ATTEMPTS,
3113
+ publicAddress: null
3114
+ };
3115
+ }
3116
+ return {
3117
+ enabled: true,
3118
+ expired: typeof record.expiresAt !== "number" || Date.now() >= record.expiresAt,
3119
+ expiresAt: record.expiresAt,
3120
+ attemptsLeft: Math.max(0, QUICK_UNLOCK_MAX_ATTEMPTS - (record.failedAttempts ?? 0)),
3121
+ publicAddress: record.publicAddress
3122
+ };
3123
+ }
3124
+ async function refreshQuickUnlockExpiry(options) {
3125
+ const { publicAddress, ttlMs, ...storageOptions } = options;
3126
+ const record = await loadQuickUnlockRecord(storageOptions);
3127
+ if (!record) return;
3128
+ if (record.publicAddress !== publicAddress) {
3129
+ await clearQuickUnlockRecord(storageOptions);
3130
+ return;
3131
+ }
3132
+ await saveQuickUnlockRecord(
3133
+ { ...record, expiresAt: Date.now() + (ttlMs ?? QUICK_UNLOCK_TTL_MS), failedAttempts: 0 },
3134
+ storageOptions
3135
+ );
3136
+ }
3137
+ async function clearQuickUnlock(options = {}) {
3138
+ await clearQuickUnlockRecord(options);
3139
+ }
3140
+ var DEVICE_PIN_PBKDF2_ITERATIONS = 6e5;
3141
+ var AES_GCM_IV_BYTES4 = 12;
3142
+ function vaultUsesPinUnlock(vault) {
3143
+ return vault.kdf === EMBEDDED_WALLET_KDF_DEVICE_PIN;
3144
+ }
3145
+ async function encryptPlaintextWithDevicePin(plaintext, pin, options) {
3146
+ assertQuickUnlockPinAllowed(pin);
3147
+ const iterations = options.iterations ?? DEVICE_PIN_PBKDF2_ITERATIONS;
3148
+ const salt = crypto.getRandomValues(new Uint8Array(32));
3149
+ const pinKey = await derivePinKey(pin, salt, iterations);
3150
+ const deviceKey = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [
3151
+ "encrypt",
3152
+ "decrypt"
3153
+ ]);
3154
+ const iv = crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES4));
3155
+ const inner = await crypto.subtle.encrypt(
3156
+ { name: "AES-GCM", iv },
3157
+ pinKey,
3158
+ new Uint8Array(serializePlaintext(plaintext))
3159
+ );
3160
+ const deviceIv = crypto.getRandomValues(new Uint8Array(AES_GCM_IV_BYTES4));
3161
+ const outer = await crypto.subtle.encrypt({ name: "AES-GCM", iv: deviceIv }, deviceKey, inner);
3162
+ const acknowledged = options.backupAcknowledged ?? false;
3163
+ return {
3164
+ version: EMBEDDED_WALLET_VAULT_VERSION,
3165
+ kdf: EMBEDDED_WALLET_KDF_DEVICE_PIN,
3166
+ credentialId: "",
3167
+ publicAddress: options.publicAddress,
3168
+ iv: toBase64(iv),
3169
+ ciphertext: toBase64(new Uint8Array(outer)),
3170
+ kdfSalt: toBase64(salt),
3171
+ kdfIterations: iterations,
3172
+ prfSalt: "",
3173
+ backupAcknowledged: acknowledged,
3174
+ backupAcknowledgedAt: acknowledged ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
3175
+ createdAt: plaintext.createdAt,
3176
+ deviceKey,
3177
+ deviceIv: toBase64(deviceIv)
3178
+ };
3179
+ }
3180
+ async function decryptDevicePinVault(vault, pin) {
3181
+ if (!vaultUsesPinUnlock(vault)) {
3182
+ throw new EmbeddedWalletVaultError("Vault does not use PIN unlock");
3183
+ }
3184
+ if (typeof pin !== "string" || !new RegExp(`^\\d{${QUICK_UNLOCK_PIN_LENGTH}}$`).test(pin)) {
3185
+ throw new EmbeddedWalletQuickUnlockError(
3186
+ "invalid_pin",
3187
+ `PIN must be exactly ${QUICK_UNLOCK_PIN_LENGTH} digits`
3188
+ );
3189
+ }
3190
+ if (!vault.deviceKey || !vault.deviceIv) {
3191
+ throw new EmbeddedWalletVaultError(
3192
+ "This wallet's device key is missing; recover it with your 24 words"
3193
+ );
3194
+ }
3195
+ let inner;
3196
+ try {
3197
+ inner = await crypto.subtle.decrypt(
3198
+ { name: "AES-GCM", iv: new Uint8Array(fromBase64(vault.deviceIv)) },
3199
+ vault.deviceKey,
3200
+ new Uint8Array(fromBase64(vault.ciphertext))
3201
+ );
3202
+ } catch (err) {
3203
+ throw new EmbeddedWalletVaultError(
3204
+ "This wallet's device layer is damaged; recover it with your 24 words",
3205
+ err
3206
+ );
3207
+ }
3208
+ const pinKey = await derivePinKey(pin, fromBase64(vault.kdfSalt), vault.kdfIterations);
3209
+ let plaintext;
3210
+ try {
3211
+ plaintext = await crypto.subtle.decrypt(
3212
+ { name: "AES-GCM", iv: new Uint8Array(fromBase64(vault.iv)) },
3213
+ pinKey,
3214
+ inner
3215
+ );
3216
+ } catch (err) {
3217
+ throw new EmbeddedWalletDecryptError(err);
3218
+ }
3219
+ return deserializePlaintext(new Uint8Array(plaintext));
3220
+ }
2893
3221
 
2894
3222
  // src/embeddedWallet/wallet.ts
2895
3223
  var activeSession = null;
2896
3224
  var activeScopeId;
3225
+ var activePlaintext = null;
3226
+ var activeUnlockWasStrong = false;
2897
3227
  function resolveScopeId(scopeId) {
2898
3228
  const trimmed = scopeId?.trim();
2899
3229
  return trimmed || void 0;
@@ -2910,6 +3240,12 @@ function vaultUsesPasskeyUnlock(vault) {
2910
3240
  function vaultUsesPasscodeUnlock(vault) {
2911
3241
  return vault.kdf === EMBEDDED_WALLET_KDF_PIN;
2912
3242
  }
3243
+ function vaultHasPasskeyUnlock(vault) {
3244
+ return Boolean(vault.passkeyWrap) || vaultUsesPasskeyUnlock(vault);
3245
+ }
3246
+ function vaultPersistsSessionCache(vault) {
3247
+ return !(vaultUsesPinUnlock(vault) || Boolean(vault.passkeyWrap));
3248
+ }
2913
3249
  function isPasscodeDecryptFailure(err) {
2914
3250
  return err instanceof EmbeddedWalletDecryptError;
2915
3251
  }
@@ -2932,6 +3268,28 @@ async function decryptVaultWithPasscodeProtected(vault, passcode) {
2932
3268
  throw err;
2933
3269
  }
2934
3270
  }
3271
+ async function decryptVaultWithPinProtected(vault, pin) {
3272
+ if (!pin) {
3273
+ throw new EmbeddedWalletVaultError("PIN is required to unlock this wallet");
3274
+ }
3275
+ await assertPasscodeUnlockAllowed(vault.publicAddress);
3276
+ try {
3277
+ const plaintext = await decryptDevicePinVault(vault, pin);
3278
+ await recordPasscodeUnlockSuccess(vault.publicAddress);
3279
+ return plaintext;
3280
+ } catch (err) {
3281
+ if (isPasscodeDecryptFailure(err)) {
3282
+ await recordPasscodeUnlockFailure(vault.publicAddress);
3283
+ }
3284
+ throw err;
3285
+ }
3286
+ }
3287
+ async function decryptVaultWithSecret(vault, secret) {
3288
+ if (vaultUsesPinUnlock(vault)) {
3289
+ return decryptVaultWithPinProtected(vault, secret.pin);
3290
+ }
3291
+ return decryptVaultWithPasscodeProtected(vault, secret.passcode);
3292
+ }
2935
3293
  async function deriveKekFromPasskeyMaterial(vault, prfOutput, authenticatorData, clientDataJSON) {
2936
3294
  const caps = detectWebAuthnPrfCapabilities();
2937
3295
  const kdf = selectEmbeddedWalletKdf(caps, prfOutput);
@@ -2987,40 +3345,27 @@ async function encryptPlaintextWithPasscode(plaintext, passcode, backupAcknowled
2987
3345
  });
2988
3346
  return { address: account.address, vault };
2989
3347
  }
2990
- async function encryptPlaintextWithPasskeyRegistration(plaintext, registration, backupAcknowledged = false) {
2991
- const previewSigner = await embeddedPlaintextToSigner(plaintext);
2992
- const [account] = await previewSigner.getAccounts();
2993
- const caps = detectWebAuthnPrfCapabilities();
2994
- const kdf = selectEmbeddedWalletKdf(caps, registration.prfOutput);
2995
- let kek;
2996
- let kdfSalt;
2997
- let prfSalt;
2998
- if (kdf === EMBEDDED_WALLET_KDF_PRF && registration.prfOutput) {
2999
- kek = await deriveKekFromPrf(registration.prfOutput);
3000
- prfSalt = registration.prfSalt;
3001
- } else {
3002
- kdfSalt = createPbkdf2Salt();
3003
- const material = createPasskeyMaterialFromAssertion(
3004
- registration.authenticatorData,
3005
- registration.clientDataJSON
3006
- );
3007
- kek = await deriveKekFromPbkdf2(material, kdfSalt);
3348
+ async function encryptPlaintextWithSecret(plaintext, secret, backupAcknowledged = false) {
3349
+ if (secret.pin != null) {
3350
+ const signer = await embeddedPlaintextToSigner(plaintext);
3351
+ const [account] = await signer.getAccounts();
3352
+ const vault = await encryptPlaintextWithDevicePin(plaintext, secret.pin, {
3353
+ publicAddress: account.address,
3354
+ backupAcknowledged
3355
+ });
3356
+ return { address: account.address, vault };
3008
3357
  }
3009
- const vault = await encryptWalletPayload(plaintext, {
3010
- kdf,
3011
- credentialId: registration.credentialId,
3012
- publicAddress: account.address,
3013
- kek,
3014
- kdfSalt,
3015
- prfSalt,
3016
- backupAcknowledged
3017
- });
3018
- return { address: account.address, vault };
3358
+ if (secret.passcode == null) {
3359
+ throw new EmbeddedWalletVaultError("A PIN (or legacy passcode) is required");
3360
+ }
3361
+ return encryptPlaintextWithPasscode(plaintext, secret.passcode, backupAcknowledged);
3019
3362
  }
3020
3363
  async function unlockVaultToSession(vault, options = {}) {
3021
3364
  const scopeId = scopeFromOptions(options);
3022
3365
  let plaintext;
3023
- if (vaultUsesPasscodeUnlock(vault)) {
3366
+ if (vaultUsesPinUnlock(vault)) {
3367
+ plaintext = await decryptVaultWithPinProtected(vault, options.pin);
3368
+ } else if (vaultUsesPasscodeUnlock(vault)) {
3024
3369
  plaintext = await decryptVaultWithPasscodeProtected(vault, options.passcode);
3025
3370
  } else {
3026
3371
  const credentialId = decodeCredentialId(vault.credentialId);
@@ -3028,14 +3373,32 @@ async function unlockVaultToSession(vault, options = {}) {
3028
3373
  const assertion = await assertPasskey({ credentialId, rpId: void 0, prfSalt });
3029
3374
  plaintext = await decryptVaultWithUnlockMaterial(vault, void 0, assertion);
3030
3375
  }
3376
+ return establishSession(vault, plaintext, scopeId, { strong: true });
3377
+ }
3378
+ async function establishSession(vault, plaintext, scopeId, options) {
3031
3379
  const signer = await embeddedPlaintextToSigner(plaintext);
3032
3380
  const [account] = await signer.getAccounts();
3033
3381
  const session = { address: account.address, vault, signer };
3034
3382
  activeSession = session;
3035
3383
  activeScopeId = scopeId;
3036
- try {
3037
- await cacheUnlockedSession({ scopeId, plaintext });
3038
- } catch {
3384
+ activePlaintext = plaintext;
3385
+ activeUnlockWasStrong = options.strong;
3386
+ if (vaultPersistsSessionCache(vault)) {
3387
+ try {
3388
+ await cacheUnlockedSession({ scopeId, plaintext });
3389
+ } catch {
3390
+ }
3391
+ } else {
3392
+ try {
3393
+ await clearUnlockedSession({ scopeId });
3394
+ } catch {
3395
+ }
3396
+ }
3397
+ if (options.strong) {
3398
+ try {
3399
+ await refreshQuickUnlockExpiry({ scopeId, publicAddress: account.address });
3400
+ } catch {
3401
+ }
3039
3402
  }
3040
3403
  return session;
3041
3404
  }
@@ -3076,7 +3439,7 @@ async function createEmbeddedWallet(options) {
3076
3439
  }
3077
3440
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
3078
3441
  const plaintext = await createHdDerivedPlaintext(createdAt);
3079
- const { address, vault } = await encryptPlaintextWithPasscode(plaintext, options.passcode);
3442
+ const { address, vault } = await encryptPlaintextWithSecret(plaintext, options);
3080
3443
  await saveVaultToIndexedDb(vault, { scopeId });
3081
3444
  lockEmbeddedWallet();
3082
3445
  activeScopeId = scopeId;
@@ -3089,7 +3452,11 @@ async function revealEmbeddedRecoveryPhrase(options = {}) {
3089
3452
  throw new EmbeddedWalletVaultError("No embedded wallet found on this device");
3090
3453
  }
3091
3454
  let plaintext;
3092
- if (vaultUsesPasscodeUnlock(vault)) {
3455
+ if ((vaultUsesPasscodeUnlock(vault) || vaultUsesPinUnlock(vault)) && !options.passcode && !options.pin && vault.passkeyWrap) {
3456
+ plaintext = await decryptPasskeyWrap(vault);
3457
+ } else if (vaultUsesPinUnlock(vault)) {
3458
+ plaintext = await decryptVaultWithPinProtected(vault, options.pin);
3459
+ } else if (vaultUsesPasscodeUnlock(vault)) {
3093
3460
  plaintext = await decryptVaultWithPasscodeProtected(vault, options.passcode);
3094
3461
  } else {
3095
3462
  const credentialId = decodeCredentialId(vault.credentialId);
@@ -3145,7 +3512,7 @@ async function recoverEmbeddedWalletFromMnemonic(options) {
3145
3512
  "Recovered wallet address does not match expectedAddress"
3146
3513
  );
3147
3514
  }
3148
- const result = await encryptPlaintextWithPasscode(plaintext, options.passcode);
3515
+ const result = await encryptPlaintextWithSecret(plaintext, options);
3149
3516
  if (result.address !== address) {
3150
3517
  throw new EmbeddedWalletVaultError("Internal error: recovered address mismatch");
3151
3518
  }
@@ -3154,41 +3521,220 @@ async function recoverEmbeddedWalletFromMnemonic(options) {
3154
3521
  activeScopeId = scopeId;
3155
3522
  return { address: result.address, vault: result.vault, keyType };
3156
3523
  }
3524
+ function activePlaintextFor(scopeId, vault) {
3525
+ if (!activePlaintext || !activeSession) return null;
3526
+ if (activeScopeId !== scopeId) return null;
3527
+ if (activeSession.address !== vault.publicAddress) return null;
3528
+ return activePlaintext;
3529
+ }
3157
3530
  async function enableEmbeddedPasskeyUnlock(options) {
3158
3531
  const scopeId = scopeFromOptions(options) ?? activeScopeId;
3159
3532
  const vault = await loadVaultForScope(scopeId);
3160
3533
  if (!vault) {
3161
3534
  throw new EmbeddedWalletVaultError("No embedded wallet found on this device");
3162
3535
  }
3163
- if (vaultUsesPasskeyUnlock(vault)) {
3536
+ if (vaultHasPasskeyUnlock(vault)) {
3164
3537
  throw new EmbeddedWalletVaultError("Passkey unlock is already enabled for this wallet");
3165
3538
  }
3166
- if (!vaultUsesPasscodeUnlock(vault)) {
3539
+ if (!vaultUsesPasscodeUnlock(vault) && !vaultUsesPinUnlock(vault)) {
3167
3540
  throw new EmbeddedWalletVaultError("Unsupported vault unlock method for passkey upgrade");
3168
3541
  }
3169
- const addressBefore = vault.publicAddress;
3170
- const backupAcknowledged = vault.backupAcknowledged;
3171
- const plaintext = await decryptVaultWithPasscodeProtected(vault, options.passcode);
3542
+ const plaintext = options.passcode != null || options.pin != null ? await decryptVaultWithSecret(vault, options) : activePlaintextFor(scopeId, vault);
3543
+ if (!plaintext) {
3544
+ throw new EmbeddedWalletVaultError("Unlock the wallet (or pass the passcode) before adding Face ID");
3545
+ }
3546
+ const prfSalt = crypto.getRandomValues(new Uint8Array(32));
3172
3547
  const registration = await registerPasskey({
3173
3548
  userId: options.userId,
3174
3549
  userName: options.userName,
3175
3550
  displayName: options.displayName,
3176
- rpId: options.rpId
3551
+ rpId: options.rpId,
3552
+ prfSalt
3177
3553
  });
3178
- const result = await encryptPlaintextWithPasskeyRegistration(
3554
+ let prfOutput = registration.prfOutput;
3555
+ if (!prfOutput) {
3556
+ try {
3557
+ const assertion = await assertPasskey({
3558
+ credentialId: registration.credentialId,
3559
+ rpId: options.rpId,
3560
+ prfSalt
3561
+ });
3562
+ prfOutput = assertion.prfOutput;
3563
+ } catch {
3564
+ prfOutput = null;
3565
+ }
3566
+ }
3567
+ if (!prfOutput) {
3568
+ throw new EmbeddedWalletPasskeyUnsupportedError();
3569
+ }
3570
+ const previewSigner = await embeddedPlaintextToSigner(plaintext);
3571
+ const [account] = await previewSigner.getAccounts();
3572
+ if (account.address !== vault.publicAddress) {
3573
+ throw new EmbeddedWalletVaultError("Passkey upgrade must not change wallet address");
3574
+ }
3575
+ const kek = await deriveKekFromPrf(prfOutput);
3576
+ const wrapped = await encryptPlaintextWithKek(plaintext, kek);
3577
+ const updated = {
3578
+ ...vault,
3579
+ passkeyWrap: {
3580
+ credentialId: encodeCredentialId(registration.credentialId),
3581
+ prfSalt: encodeCredentialId(prfSalt),
3582
+ rpId: options.rpId,
3583
+ iv: wrapped.iv,
3584
+ ciphertext: wrapped.ciphertext,
3585
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
3586
+ }
3587
+ };
3588
+ await saveVaultToIndexedDb(updated, { scopeId });
3589
+ if (activeSession && activeSession.address === updated.publicAddress) {
3590
+ activeSession = { ...activeSession, vault: updated };
3591
+ }
3592
+ return { address: updated.publicAddress, vault: updated };
3593
+ }
3594
+ async function setEmbeddedWalletPin(options) {
3595
+ const scopeId = scopeFromOptions(options) ?? activeScopeId;
3596
+ const vault = await loadVaultForScope(scopeId);
3597
+ if (!vault) {
3598
+ throw new EmbeddedWalletVaultError("No embedded wallet found on this device");
3599
+ }
3600
+ if (!vaultUsesPasscodeUnlock(vault) && !vaultUsesPinUnlock(vault)) {
3601
+ throw new EmbeddedWalletVaultError("This wallet type cannot switch to a PIN");
3602
+ }
3603
+ let plaintext = null;
3604
+ if (options.currentPin != null || options.passcode != null) {
3605
+ plaintext = await decryptVaultWithSecret(vault, {
3606
+ pin: options.currentPin,
3607
+ passcode: options.passcode
3608
+ });
3609
+ } else if (activeUnlockWasStrong) {
3610
+ plaintext = activePlaintextFor(scopeId, vault);
3611
+ }
3612
+ if (!plaintext) {
3613
+ throw new EmbeddedWalletVaultError("Unlock the wallet before changing the PIN");
3614
+ }
3615
+ const result = await encryptPlaintextWithSecret(
3179
3616
  plaintext,
3180
- registration,
3181
- backupAcknowledged
3617
+ { pin: options.pin },
3618
+ vault.backupAcknowledged
3182
3619
  );
3183
- if (result.address !== addressBefore) {
3184
- throw new EmbeddedWalletVaultError("Passkey upgrade must not change wallet address");
3620
+ if (result.address !== vault.publicAddress) {
3621
+ throw new EmbeddedWalletVaultError("Changing the PIN must not change the wallet address");
3622
+ }
3623
+ const updated = {
3624
+ ...result.vault,
3625
+ backupAcknowledgedAt: vault.backupAcknowledgedAt,
3626
+ createdAt: vault.createdAt,
3627
+ passkeyWrap: vault.passkeyWrap
3628
+ };
3629
+ if (!updated.passkeyWrap) delete updated.passkeyWrap;
3630
+ await saveVaultToIndexedDb(updated, { scopeId });
3631
+ await clearQuickUnlock({ scopeId }).catch(() => void 0);
3632
+ if (activeSession && activeSession.address === updated.publicAddress) {
3633
+ activeSession = { ...activeSession, vault: updated };
3185
3634
  }
3186
- await saveVaultToIndexedDb(result.vault, { scopeId });
3187
- if (activeSession) {
3188
- activeSession = { ...activeSession, vault: result.vault };
3635
+ return { address: updated.publicAddress, vault: updated };
3636
+ }
3637
+ async function disableEmbeddedPasskeyUnlock(options = {}) {
3638
+ const scopeId = scopeFromOptions(options) ?? activeScopeId;
3639
+ const vault = await loadVaultForScope(scopeId);
3640
+ if (!vault) {
3641
+ throw new EmbeddedWalletVaultError("No embedded wallet found on this device");
3189
3642
  }
3190
- lockEmbeddedWallet();
3191
- return result;
3643
+ if (!vault.passkeyWrap) {
3644
+ return vault;
3645
+ }
3646
+ const updated = { ...vault };
3647
+ delete updated.passkeyWrap;
3648
+ await saveVaultToIndexedDb(updated, { scopeId });
3649
+ if (activeSession && activeSession.address === updated.publicAddress) {
3650
+ activeSession = { ...activeSession, vault: updated };
3651
+ }
3652
+ return updated;
3653
+ }
3654
+ async function decryptPasskeyWrap(vault) {
3655
+ const wrap = vault.passkeyWrap;
3656
+ if (!wrap) {
3657
+ throw new EmbeddedWalletVaultError("Face ID is not set up for this wallet");
3658
+ }
3659
+ const prfSalt = decodeCredentialId(wrap.prfSalt);
3660
+ const assertion = await assertPasskey({
3661
+ credentialId: decodeCredentialId(wrap.credentialId),
3662
+ rpId: wrap.rpId,
3663
+ prfSalt
3664
+ });
3665
+ if (!assertion.prfOutput) {
3666
+ throw new EmbeddedWalletPasskeyUnsupportedError(
3667
+ "This browser did not return the passkey secret; unlock with your passcode"
3668
+ );
3669
+ }
3670
+ const kek = await deriveKekFromPrf(assertion.prfOutput);
3671
+ const plaintext = await decryptPlaintextWithKek(wrap.iv, wrap.ciphertext, kek);
3672
+ const signer = await embeddedPlaintextToSigner(plaintext);
3673
+ const [account] = await signer.getAccounts();
3674
+ if (account.address !== vault.publicAddress) {
3675
+ throw new EmbeddedWalletVaultError("Passkey opened a key for a different address");
3676
+ }
3677
+ return plaintext;
3678
+ }
3679
+ async function unlockEmbeddedWalletWithPasskey(options = {}) {
3680
+ const scopeId = scopeFromOptions(options) ?? activeScopeId;
3681
+ const vault = await loadVaultForScope(scopeId);
3682
+ if (!vault) {
3683
+ throw new EmbeddedWalletVaultError("No embedded wallet found on this device");
3684
+ }
3685
+ if (vaultUsesPasskeyUnlock(vault)) {
3686
+ return unlockVaultToSession(vault, { scopeId });
3687
+ }
3688
+ const plaintext = await decryptPasskeyWrap(vault);
3689
+ return establishSession(vault, plaintext, scopeId, { strong: true });
3690
+ }
3691
+ async function setEmbeddedQuickUnlockPin(options) {
3692
+ const scopeId = scopeFromOptions(options) ?? activeScopeId;
3693
+ const vault = await loadVaultForScope(scopeId);
3694
+ if (!vault) {
3695
+ throw new EmbeddedWalletVaultError("No embedded wallet found on this device");
3696
+ }
3697
+ const plaintext = activePlaintextFor(scopeId, vault);
3698
+ if (!plaintext || !activeUnlockWasStrong) {
3699
+ throw new EmbeddedWalletQuickUnlockError(
3700
+ "no_session",
3701
+ "Unlock with Face ID or your passcode before choosing a PIN"
3702
+ );
3703
+ }
3704
+ await createQuickUnlockRecord({
3705
+ scopeId,
3706
+ plaintext,
3707
+ publicAddress: vault.publicAddress,
3708
+ pin: options.pin
3709
+ });
3710
+ return getQuickUnlockStatus({ scopeId });
3711
+ }
3712
+ async function unlockEmbeddedWalletWithPin(options) {
3713
+ const scopeId = scopeFromOptions(options) ?? activeScopeId;
3714
+ const vault = await loadVaultForScope(scopeId);
3715
+ if (!vault) {
3716
+ throw new EmbeddedWalletVaultError("No embedded wallet found on this device");
3717
+ }
3718
+ const opened = await openQuickUnlockRecord({ scopeId, pin: options.pin });
3719
+ if (opened.publicAddress !== vault.publicAddress) {
3720
+ await clearQuickUnlock({ scopeId }).catch(() => void 0);
3721
+ throw new EmbeddedWalletQuickUnlockError("not_set", "PIN belongs to a different wallet");
3722
+ }
3723
+ const signer = await embeddedPlaintextToSigner(opened.plaintext);
3724
+ const [account] = await signer.getAccounts();
3725
+ if (account.address !== vault.publicAddress) {
3726
+ await clearQuickUnlock({ scopeId }).catch(() => void 0);
3727
+ throw new EmbeddedWalletQuickUnlockError("not_set", "PIN record does not match this wallet");
3728
+ }
3729
+ return establishSession(vault, opened.plaintext, scopeId, { strong: false });
3730
+ }
3731
+ async function getEmbeddedQuickUnlockStatus(options = {}) {
3732
+ const scopeId = scopeFromOptions(options) ?? activeScopeId;
3733
+ return getQuickUnlockStatus({ scopeId });
3734
+ }
3735
+ async function clearEmbeddedQuickUnlockPin(options = {}) {
3736
+ const scopeId = scopeFromOptions(options) ?? activeScopeId;
3737
+ await clearQuickUnlock({ scopeId });
3192
3738
  }
3193
3739
  async function unlockEmbeddedWallet(options = {}) {
3194
3740
  const scopeId = scopeFromOptions(options) ?? activeScopeId;
@@ -3218,12 +3764,16 @@ async function tryRestoreUnlockedSession(options = {}) {
3218
3764
  const session = { address: account.address, vault, signer };
3219
3765
  activeSession = session;
3220
3766
  activeScopeId = scopeId;
3767
+ activePlaintext = plaintext;
3768
+ activeUnlockWasStrong = false;
3221
3769
  return session;
3222
3770
  }
3223
3771
  function lockEmbeddedWallet() {
3224
3772
  const scopeId = activeScopeId;
3225
3773
  activeSession = null;
3226
3774
  activeScopeId = void 0;
3775
+ activePlaintext = null;
3776
+ activeUnlockWasStrong = false;
3227
3777
  void clearUnlockedSession({ scopeId }).catch(() => void 0);
3228
3778
  }
3229
3779
  function getEmbeddedWalletSession() {
@@ -3251,7 +3801,7 @@ async function acknowledgeEmbeddedBackup(options = {}) {
3251
3801
  if (activeSession) {
3252
3802
  activeSession = { ...activeSession, vault: updated };
3253
3803
  }
3254
- return exportEncryptedBackup(updated);
3804
+ return vaultUsesPinUnlock(updated) ? null : exportEncryptedBackup(updated);
3255
3805
  }
3256
3806
  function downloadEmbeddedBackupFile(backup, filename) {
3257
3807
  const blob = new Blob([serializeBackupFile(backup)], { type: "application/json" });
@@ -3280,6 +3830,7 @@ async function clearEmbeddedWallet(options = {}) {
3280
3830
  const scopeId = scopeFromOptions(options) ?? activeScopeId;
3281
3831
  lockEmbeddedWallet();
3282
3832
  await clearUnlockedSession({ scopeId });
3833
+ await clearQuickUnlock({ scopeId }).catch(() => void 0);
3283
3834
  await clearVaultFromIndexedDb({ scopeId });
3284
3835
  }
3285
3836
 
@@ -3562,6 +4113,6 @@ function sleep(ms) {
3562
4113
  return new Promise((resolve) => setTimeout(resolve, ms));
3563
4114
  }
3564
4115
 
3565
- export { ATTESTATION_TYPE_CITIZENSHIP_APPLICATION, ATTESTATION_TYPE_RECOVERY, ApplicationStatus, BECH32_PREFIX, CHAIN_COIN_TYPE, CitizenTxError, DEFAULT_CHAIN_ID, DEFAULT_REST_URL, DEFAULT_RPC_URL, EMBEDDED_WALLET_KDF_PBKDF2, EMBEDDED_WALLET_KDF_PIN, EMBEDDED_WALLET_KDF_PRF, EMBEDDED_WALLET_KEY_DIRECT_ENTROPY, EMBEDDED_WALLET_KEY_HD_DERIVED, EMBEDDED_WALLET_PASSCODE_MAX_LENGTH, EMBEDDED_WALLET_PASSCODE_MIN_LENGTH, EMBEDDED_WALLET_PASSKEY_PBKDF2_ITERATIONS, EMBEDDED_WALLET_PIN_PBKDF2_ITERATIONS, EMBEDDED_WALLET_RECOVERY_PHRASE_DIRECT_ENTROPY_WARNING, EMBEDDED_WALLET_RECOVERY_PHRASE_GENERAL_WARNING, EMBEDDED_WALLET_SESSION_TTL_MS, EMBEDDED_WALLET_VAULT_VERSION, EmbeddedWalletBackupRequiredError, EmbeddedWalletDecryptError, EmbeddedWalletLockoutError, EmbeddedWalletVaultError, EmbeddedWalletWeakPasscodeError, InvalidChainConfigError, MsgClaimReward, MsgSubmitApplication, MsgSubmitRecoveryAttestation, PASSCODE_LOCKOUT_FAILURE_THRESHOLD, PASSCODE_LOCKOUT_INITIAL_MS, PASSCODE_LOCKOUT_MAX_MS, RecoveryAttestationStatus, RestQueryError, RpcConnectionError, UKDR_DECIMALS, UKDR_DISPLAY_DENOM, UKDR_MINIMAL_DENOM, VAULT_LEGACY_KEY, WALLETCONNECT_COSMOS_METHODS, WALLETCONNECT_COSMOS_NAMESPACE, WEBAUTHN_RP_NAME, WalletAccountError, WalletConnectNotInitializedError, WalletConnectSessionError, WalletConnectSigningError, WalletConnectionError, WalletConnectionRejectedError, WalletNotInstalledError, WebAuthnUnavailableError, WebAuthnUserCancelledError, acknowledgeEmbeddedBackup, addressFromHdMnemonic, addressFromPrivateKey, assertPasscodeAllowedForCreation, assertPasscodeUnlockAllowed, assertPasskey, assertValidPasscode, assertValidRecoveryMnemonic, assertVaultPermitsTransaction, attestationSignPayload, broadcastAndConfirmTx, buildClaimRewardMsg, buildKingdomChainInfo, buildRequiredCosmosNamespaces, buildSendUkdrMsg, buildSubmitApplicationMsg, cacheUnlockedSession, citizenTxErrorMessage, clearEmbeddedWallet, clearPasscodeLockoutRecord, clearSessionCacheRecord, clearUnlockedSession, clearVaultFromIndexedDb, computePasscodeLockoutDurationMs, connectCosmostation, connectKeplr, connectLeap, connectWalletConnect, createBrowserSigningClient, createEmbeddedWallet, createHdDerivedPlaintext, createKingdomChainRegistry, createPasskeyMaterialFromAssertion, createPbkdf2Salt, createWalletConnectOfflineSigner, decodeCredentialId, decodeDirectEntropyMnemonic, decryptWalletPayload, defaultEmbeddedHdPath, defaultUkdrTxFee, deriveKekFromPasscode, deriveKekFromPbkdf2, deriveKekFromPrf, derivePrivateKeyFromHdMnemonic, detectRecoveryMnemonicKeyType, detectWebAuthnPrfCapabilities, disconnectWalletConnect, downloadEmbeddedBackupFile, embeddedPlaintextToSigner, enableEmbeddedPasskeyUnlock, encodeCredentialId, encodeDirectEntropyMnemonic, encryptWalletPayload, evaluatePasscodeStrength, exportEncryptedBackup, fetchFeeGrantGranter, fetchUkdrBalance, fetchUnclaimedFinalizedRewards, formatUkdrAsKdr, getCosmostationKeplrApi, getEmbeddedOfflineSigner, getEmbeddedWalletSession, getPasscodeLockoutState, hasEmbeddedWallet, hasLegacyEmbeddedWallet, hasMixedCharacterClasses, importEmbeddedBackup, initWalletConnectClient, isCosmostationAvailable, isKeplrAvailable, isLeapAvailable, loadPasscodeLockoutRecord, loadSessionCacheRecord, loadVaultFromIndexedDb, lockEmbeddedWallet, markVaultBackupAcknowledged, migrateLegacyEmbeddedWallet, normalizePasscode, normalizeRecoveryMnemonic, parseEncryptedBackup, parseKdrToUkdr, parseWalletConnectAccount, plaintextFromRecoveryMnemonic, providerSeedFromHex, publicKeyFromPrivateSeed, readPrfOutput, recordPasscodeUnlockFailure, recordPasscodeUnlockSuccess, recoverEmbeddedWalletFromMnemonic, recoveryMnemonicAddress, recoveryMnemonicFromPlaintext, registerPasskey, resolvePlaintextKeyType, resolveVaultStorageKey, restoreCachedSessionPlaintext, restoreWalletConnectSession, revealEmbeddedRecoveryPhrase, savePasscodeLockoutRecord, saveSessionCacheRecord, saveVaultToIndexedDb, selectEmbeddedWalletKdf, serializeBackupFile, signAttestationPayload, signCitizenshipAttestation, suggestAndConnect, toWalletConnectCosmosChainId, tryRestoreUnlockedSession, ukdrCoin, unlockEmbeddedWallet, validateChainConfig, vaultUsesPasscodeUnlock, vaultUsesPasskeyUnlock };
4116
+ export { ATTESTATION_TYPE_CITIZENSHIP_APPLICATION, ATTESTATION_TYPE_RECOVERY, ApplicationStatus, BECH32_PREFIX, CHAIN_COIN_TYPE, CitizenTxError, DEFAULT_CHAIN_ID, DEFAULT_REST_URL, DEFAULT_RPC_URL, DEVICE_PIN_PBKDF2_ITERATIONS, EMBEDDED_WALLET_KDF_DEVICE_PIN, EMBEDDED_WALLET_KDF_PBKDF2, EMBEDDED_WALLET_KDF_PIN, EMBEDDED_WALLET_KDF_PRF, EMBEDDED_WALLET_KEY_DIRECT_ENTROPY, EMBEDDED_WALLET_KEY_HD_DERIVED, EMBEDDED_WALLET_PASSCODE_MAX_LENGTH, EMBEDDED_WALLET_PASSCODE_MIN_LENGTH, EMBEDDED_WALLET_PASSKEY_PBKDF2_ITERATIONS, EMBEDDED_WALLET_PIN_PBKDF2_ITERATIONS, EMBEDDED_WALLET_RECOVERY_PHRASE_DIRECT_ENTROPY_WARNING, EMBEDDED_WALLET_RECOVERY_PHRASE_GENERAL_WARNING, EMBEDDED_WALLET_SESSION_TTL_MS, EMBEDDED_WALLET_VAULT_VERSION, EmbeddedWalletBackupRequiredError, EmbeddedWalletDecryptError, EmbeddedWalletLockoutError, EmbeddedWalletPasskeyUnsupportedError, EmbeddedWalletQuickUnlockError, EmbeddedWalletVaultError, EmbeddedWalletWeakPasscodeError, InvalidChainConfigError, MsgClaimReward, MsgSubmitApplication, MsgSubmitRecoveryAttestation, PASSCODE_LOCKOUT_FAILURE_THRESHOLD, PASSCODE_LOCKOUT_INITIAL_MS, PASSCODE_LOCKOUT_MAX_MS, QUICK_UNLOCK_MAX_ATTEMPTS, QUICK_UNLOCK_PBKDF2_ITERATIONS, QUICK_UNLOCK_PIN_LENGTH, QUICK_UNLOCK_TTL_MS, RecoveryAttestationStatus, RestQueryError, RpcConnectionError, UKDR_DECIMALS, UKDR_DISPLAY_DENOM, UKDR_MINIMAL_DENOM, VAULT_LEGACY_KEY, WALLETCONNECT_COSMOS_METHODS, WALLETCONNECT_COSMOS_NAMESPACE, WEBAUTHN_RP_NAME, WalletAccountError, WalletConnectNotInitializedError, WalletConnectSessionError, WalletConnectSigningError, WalletConnectionError, WalletConnectionRejectedError, WalletNotInstalledError, WebAuthnUnavailableError, WebAuthnUserCancelledError, acknowledgeEmbeddedBackup, addressFromHdMnemonic, addressFromPrivateKey, assertPasscodeAllowedForCreation, assertPasscodeUnlockAllowed, assertPasskey, assertQuickUnlockPinAllowed, assertValidPasscode, assertValidRecoveryMnemonic, assertVaultPermitsTransaction, attestationSignPayload, broadcastAndConfirmTx, buildClaimRewardMsg, buildKingdomChainInfo, buildRequiredCosmosNamespaces, buildSendUkdrMsg, buildSubmitApplicationMsg, cacheUnlockedSession, citizenTxErrorMessage, clearEmbeddedQuickUnlockPin, clearEmbeddedWallet, clearPasscodeLockoutRecord, clearQuickUnlock, clearQuickUnlockRecord, clearSessionCacheRecord, clearUnlockedSession, clearVaultFromIndexedDb, computePasscodeLockoutDurationMs, connectCosmostation, connectKeplr, connectLeap, connectWalletConnect, createBrowserSigningClient, createEmbeddedWallet, createHdDerivedPlaintext, createKingdomChainRegistry, createPasskeyMaterialFromAssertion, createPbkdf2Salt, createQuickUnlockRecord, createWalletConnectOfflineSigner, decodeCredentialId, decodeDirectEntropyMnemonic, decryptDevicePinVault, decryptPlaintextWithKek, decryptWalletPayload, defaultEmbeddedHdPath, defaultUkdrTxFee, deriveKekFromPasscode, deriveKekFromPbkdf2, deriveKekFromPrf, derivePinKey, derivePrivateKeyFromHdMnemonic, deserializePlaintext, detectRecoveryMnemonicKeyType, detectWebAuthnPrfCapabilities, disableEmbeddedPasskeyUnlock, disconnectWalletConnect, downloadEmbeddedBackupFile, embeddedPlaintextToSigner, enableEmbeddedPasskeyUnlock, encodeCredentialId, encodeDirectEntropyMnemonic, encryptPlaintextWithDevicePin, encryptPlaintextWithKek, encryptWalletPayload, evaluatePasscodeStrength, exportEncryptedBackup, fetchFeeGrantGranter, fetchUkdrBalance, fetchUnclaimedFinalizedRewards, formatUkdrAsKdr, getCosmostationKeplrApi, getEmbeddedOfflineSigner, getEmbeddedQuickUnlockStatus, getEmbeddedWalletSession, getPasscodeLockoutState, getQuickUnlockStatus, hasEmbeddedWallet, hasLegacyEmbeddedWallet, hasMixedCharacterClasses, importEmbeddedBackup, initWalletConnectClient, isCosmostationAvailable, isKeplrAvailable, isLeapAvailable, isTrivialPin, loadPasscodeLockoutRecord, loadQuickUnlockRecord, loadSessionCacheRecord, loadVaultFromIndexedDb, lockEmbeddedWallet, markVaultBackupAcknowledged, migrateLegacyEmbeddedWallet, normalizePasscode, normalizeRecoveryMnemonic, openQuickUnlockRecord, parseEncryptedBackup, parseKdrToUkdr, parseWalletConnectAccount, plaintextFromRecoveryMnemonic, providerSeedFromHex, publicKeyFromPrivateSeed, readPrfOutput, recordPasscodeUnlockFailure, recordPasscodeUnlockSuccess, recoverEmbeddedWalletFromMnemonic, recoveryMnemonicAddress, recoveryMnemonicFromPlaintext, refreshQuickUnlockExpiry, registerPasskey, resolvePlaintextKeyType, resolveVaultStorageKey, restoreCachedSessionPlaintext, restoreWalletConnectSession, revealEmbeddedRecoveryPhrase, savePasscodeLockoutRecord, saveQuickUnlockRecord, saveSessionCacheRecord, saveVaultToIndexedDb, selectEmbeddedWalletKdf, serializeBackupFile, serializePlaintext, setEmbeddedQuickUnlockPin, setEmbeddedWalletPin, signAttestationPayload, signCitizenshipAttestation, suggestAndConnect, toWalletConnectCosmosChainId, tryRestoreUnlockedSession, ukdrCoin, unlockEmbeddedWallet, unlockEmbeddedWalletWithPasskey, unlockEmbeddedWalletWithPin, validateChainConfig, vaultHasPasskeyUnlock, vaultUsesPasscodeUnlock, vaultUsesPasskeyUnlock, vaultUsesPinUnlock };
3566
4117
  //# sourceMappingURL=index.js.map
3567
4118
  //# sourceMappingURL=index.js.map