@anywalletkit/extension-kit 0.3.2 → 0.3.5

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.cjs CHANGED
@@ -223,6 +223,8 @@ var aadDekV1 = (kdf) => `forgewallet-vault/1/dek/${kdf.name}/${kdf.iterations}/$
223
223
  var aadDekV2 = (kdf) => `forgewallet-vault/2/dek/scrypt/${kdf.N}/${kdf.r}/${kdf.p}/${kdf.salt}`;
224
224
  var aadPasskey = (id) => `forgewallet-vault/2/passkey/${id}`;
225
225
  var aadSecret = (id) => `forgewallet-vault/secret/${id}`;
226
+ var AAD_DEK_CHECK = "forgewallet-vault/dek-check";
227
+ var DEK_CHECK = "forgewallet-vault/dek-check/1";
226
228
  var HKDF_INFO = "forgewallet-vault/2/passkey";
227
229
  var Vault = class {
228
230
  _storage;
@@ -436,7 +438,7 @@ var Vault = class {
436
438
  const key = await this._importDek(dek);
437
439
  return this._exclusive(async () => {
438
440
  const envelope = await this._load();
439
- if (Object.keys(envelope.secrets).length > 0) await this._requireDek(dek, envelope);
441
+ if (envelope.dekCheck !== void 0 || Object.keys(envelope.secrets).length > 0) await this._requireDek(dek, envelope);
440
442
  if (!(sourceId in envelope.secrets) && Object.keys(envelope.secrets).length >= VAULT_LIMITS.secrets) {
441
443
  throw new VaultError(`A vault holds at most ${VAULT_LIMITS.secrets} secrets.`, "invalid-input");
442
444
  }
@@ -489,19 +491,31 @@ var Vault = class {
489
491
  if (this._kdf === "pbkdf2") {
490
492
  const kdf2 = { name: "PBKDF2-SHA256", iterations: this._iterations, salt: toBase64(salt) };
491
493
  const kek2 = await this._derivePbkdf2(password, salt, this._iterations);
492
- return { v: 1, kdf: kdf2, dek: await this._seal(kek2, dek, aadDekV1(kdf2)), secrets, createdAt };
494
+ return { v: 1, kdf: kdf2, dek: await this._seal(kek2, dek, aadDekV1(kdf2)), secrets, dekCheck: await this._sealDekCheck(dek), createdAt };
493
495
  }
494
496
  const kdf = { name: "scrypt", ...this._scrypt, salt: toBase64(salt) };
495
497
  const kek = await this._deriveScrypt(password, salt, kdf);
496
- return { v: 2, kdf, dek: await this._seal(kek, dek, aadDekV2(kdf)), secrets, passkeys, createdAt };
498
+ return { v: 2, kdf, dek: await this._seal(kek, dek, aadDekV2(kdf)), secrets, dekCheck: await this._sealDekCheck(dek), passkeys, createdAt };
499
+ }
500
+ /** The DEK check box: {@link DEK_CHECK} sealed under `dek`. */
501
+ async _sealDekCheck(dek) {
502
+ return this._seal(await this._importDek(dek), new TextEncoder().encode(DEK_CHECK), AAD_DEK_CHECK);
497
503
  }
498
504
  /**
499
- * The caller's DEK must open this envelope's secrets — it is the key the password protects, not
500
- * any 32 bytes. An empty vault has nothing to prove it with, so it is refused rather than trusted.
505
+ * The caller's DEK must open this envelope's DEK check (or, in an envelope written before it, its
506
+ * first secret) — it is the key the password protects, not any 32 bytes. An old empty envelope has
507
+ * nothing to prove it with, so it is refused rather than trusted.
501
508
  */
502
509
  async _requireDek(dek, envelope) {
503
510
  const ids = Object.keys(envelope.secrets);
504
511
  const key = await this._importDek(dek);
512
+ if (envelope.dekCheck !== void 0) {
513
+ const check = await this._open(key, envelope.dekCheck, AAD_DEK_CHECK, "locked");
514
+ const ok = new TextDecoder().decode(check) === DEK_CHECK;
515
+ (0, import_core.zeroize)(check);
516
+ if (!ok) throw new VaultError("The vault key does not open this entry; lock and unlock again.", "locked");
517
+ return;
518
+ }
505
519
  if (ids.length === 0) throw new VaultError("Add a secret to the vault before a passkey: an empty vault cannot prove the key is its own.", "invalid-input");
506
520
  const probe = await this._open(key, envelope.secrets[ids[0]], aadSecret(ids[0]), "locked");
507
521
  (0, import_core.zeroize)(probe);
@@ -571,13 +585,13 @@ function isEnvelopeV1(x) {
571
585
  if (typeof x !== "object" || x === null) return false;
572
586
  const e = x;
573
587
  const kdf = e.kdf;
574
- return e.v === 1 && typeof kdf === "object" && kdf !== null && kdf.name === "PBKDF2-SHA256" && Number.isInteger(kdf.iterations) && typeof kdf.salt === "string" && isBox(e.dek) && typeof e.secrets === "object" && e.secrets !== null && Object.values(e.secrets).every(isBox);
588
+ return e.v === 1 && typeof kdf === "object" && kdf !== null && kdf.name === "PBKDF2-SHA256" && Number.isInteger(kdf.iterations) && typeof kdf.salt === "string" && isBox(e.dek) && typeof e.secrets === "object" && e.secrets !== null && Object.values(e.secrets).every(isBox) && (e.dekCheck === void 0 || isBox(e.dekCheck));
575
589
  }
576
590
  function isEnvelopeV2(x) {
577
591
  if (typeof x !== "object" || x === null) return false;
578
592
  const e = x;
579
593
  const kdf = e.kdf;
580
- return e.v === 2 && typeof kdf === "object" && kdf !== null && kdf.name === "scrypt" && Number.isInteger(kdf.N) && Number.isInteger(kdf.r) && Number.isInteger(kdf.p) && typeof kdf.salt === "string" && isBox(e.dek) && typeof e.secrets === "object" && e.secrets !== null && Object.values(e.secrets).every(isBox) && Array.isArray(e.passkeys) && e.passkeys.every((p) => typeof p === "object" && p !== null && typeof p.id === "string" && typeof p.label === "string" && isBox(p.dek));
594
+ return e.v === 2 && typeof kdf === "object" && kdf !== null && kdf.name === "scrypt" && Number.isInteger(kdf.N) && Number.isInteger(kdf.r) && Number.isInteger(kdf.p) && typeof kdf.salt === "string" && isBox(e.dek) && typeof e.secrets === "object" && e.secrets !== null && Object.values(e.secrets).every(isBox) && (e.dekCheck === void 0 || isBox(e.dekCheck)) && Array.isArray(e.passkeys) && e.passkeys.every((p) => typeof p === "object" && p !== null && typeof p.id === "string" && typeof p.label === "string" && isBox(p.dek));
581
595
  }
582
596
  function isBox(x) {
583
597
  return typeof x === "object" && x !== null && typeof x.iv === "string" && typeof x.data === "string";
@@ -592,7 +606,7 @@ function envelopeProblem(e) {
592
606
  if (secrets.length > VAULT_LIMITS.secrets) return `${secrets.length} secrets > ${VAULT_LIMITS.secrets}`;
593
607
  const passkeys = e.v === 2 ? e.passkeys : [];
594
608
  if (passkeys.length > VAULT_LIMITS.passkeys) return `${passkeys.length} passkeys > ${VAULT_LIMITS.passkeys}`;
595
- for (const box of [e.dek, ...secrets, ...passkeys.map((p) => p.dek)]) {
609
+ for (const box of [e.dek, ...e.dekCheck ? [e.dekCheck] : [], ...secrets, ...passkeys.map((p) => p.dek)]) {
596
610
  if (box.iv.length > VAULT_LIMITS.boxChars || box.data.length > VAULT_LIMITS.boxChars) return `a sealed box above ${VAULT_LIMITS.boxChars} characters`;
597
611
  }
598
612
  if (JSON.stringify(e).length > VAULT_LIMITS.envelopeChars) return `envelope above ${VAULT_LIMITS.envelopeChars} characters`;
@@ -1828,6 +1842,12 @@ function outgrown(shown, now) {
1828
1842
  if ("gasPrice" in now) return shown.gasPrice === void 0 || now.gasPrice > big(shown.gasPrice);
1829
1843
  return shown.maxFeePerGas === void 0 || now.base + now.tip > big(shown.maxFeePerGas);
1830
1844
  }
1845
+ var STALE_FEE_FACTOR = 4n;
1846
+ function overpriced(shown, fresh) {
1847
+ if (shown.gasPrice !== void 0 && fresh.gasPrice !== void 0) return big(shown.gasPrice) > STALE_FEE_FACTOR * big(fresh.gasPrice);
1848
+ if (shown.maxFeePerGas !== void 0 && fresh.maxFeePerGas !== void 0) return big(shown.maxFeePerGas) > STALE_FEE_FACTOR * big(fresh.maxFeePerGas);
1849
+ return false;
1850
+ }
1831
1851
  async function prepareTransaction(deps, network, from, tx) {
1832
1852
  const call = { from, to: tx.to, value: hex(BigInt(tx.value)), ...tx.data ? { data: tx.data } : {} };
1833
1853
  const [nonceHex, block, gasHex] = await Promise.all([
@@ -1873,6 +1893,8 @@ function createSignHandler(deps) {
1873
1893
  await deps.approvals.request({ origin, chain: network.caip2, kind: info.kind, payload: { ...payload, prepared: shown, repriced: true } });
1874
1894
  continue;
1875
1895
  }
1896
+ const fresh = withFees(network.chainId, nonce, big(shown.gasLimit), fees);
1897
+ if (overpriced(shown, fresh)) shown = fresh;
1876
1898
  const handle2 = await deps.signerFor(info.account, network);
1877
1899
  let raw;
1878
1900
  try {
@@ -2129,13 +2151,14 @@ var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "action-required", "re
2129
2151
  function parseSwapId(id) {
2130
2152
  if (!id.startsWith(`${import_protocol_swap2_core2.SWAP2_ID_PREFIX}.`)) return null;
2131
2153
  const parts = id.slice(import_protocol_swap2_core2.SWAP2_ID_PREFIX.length + 1).split(".");
2132
- if (parts.length < 2 || parts.length > 4 || !parts[0] || !parts[1]) return null;
2154
+ if (parts.length < 2 || parts.length > 5 || !parts[0] || !parts[1]) return null;
2155
+ if (parts[4] !== void 0 && (parts[4] !== "ok" || !parts[3])) return null;
2133
2156
  const provider = decodeURIComponent(parts[0]);
2134
2157
  const intentId = decodeURIComponent(parts[1]);
2135
2158
  const sourceTxHash = parts[2] ? decodeURIComponent(parts[2]) : void 0;
2136
2159
  const destTxHash = parts[3] ? decodeURIComponent(parts[3]) : void 0;
2137
2160
  if (destTxHash && !sourceTxHash) return null;
2138
- return { provider, intentId, ...sourceTxHash ? { sourceTxHash } : {}, ...destTxHash ? { destTxHash } : {} };
2161
+ return { provider, intentId, ...sourceTxHash ? { sourceTxHash } : {}, ...destTxHash ? { destTxHash } : {}, ...parts[4] !== void 0 ? { destTxConfirmed: true } : {} };
2139
2162
  }
2140
2163
  var SwapsStore = class {
2141
2164
  constructor(storage) {