@qntx/wallet-worker 0.6.0 → 0.7.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.
@@ -94,14 +94,11 @@ var __chunks = (base, ids, nodes, entry) => {
94
94
  __chunkSeen ||= {};
95
95
  __preload(ids[entry], 1);
96
96
  };
97
- __chunks(import.meta.url,["1qnkp5rr","gs57sjgx","1vpxmqwn","366p4fej","gsare3mw"],[["./kernel.worker.js",3],["./signer-gs57sjgx.js",3,4],["./browser-1vpxmqwn.js",4],["./worker-366p4fej.js"],["./worker-gsare3mw.js"]],0);
97
+ __chunks(import.meta.url,["y76qxfny","gs57sjgx","1vpxmqwn","366p4fej","gsare3mw"],[["./kernel.worker.js",3],["./signer-gs57sjgx.js",3,4],["./browser-1vpxmqwn.js",4],["./worker-366p4fej.js"],["./worker-gsare3mw.js"]],0);
98
98
  // ../../node_modules/.bun/@qntx+nostr@0.15.3+ea9f70ecde856c26/node_modules/@qntx/nostr/dist/util-BcRBO6o-.mjs
99
99
  var NostrError = class extends Error {
100
100
  name = "NostrError";
101
101
  };
102
- function errorMessage(error) {
103
- return error instanceof Error ? error.message : String(error);
104
- }
105
102
  var HexError = class extends NostrError {
106
103
  name = "HexError";
107
104
  };
@@ -1856,7 +1853,7 @@ class KernelError extends Error {
1856
1853
  this.corrupted = corrupted;
1857
1854
  }
1858
1855
  }
1859
- // ../wallet/dist/core-Dmz5SbyJ.mjs
1856
+ // ../wallet/dist/core-Cq5h9X0X.mjs
1860
1857
  var ValidationError = class extends Error {
1861
1858
  name = "ValidationError";
1862
1859
  };
@@ -1997,6 +1994,7 @@ var publicKey = str(64, /^[0-9a-f]{64}$/);
1997
1994
  var credentialId = str(1364, /^[A-Za-z0-9_-]+$/);
1998
1995
  var safeTime = int(0, Number.MAX_SAFE_INTEGER);
1999
1996
  var groupIndex = int(0, 2147483647);
1997
+ var identityIndex = int(0, 2147483646);
2000
1998
  var factor = union(obj({ kind: literal("hardware") }), obj({
2001
1999
  kind: literal("password"),
2002
2000
  password: bytes(1, 1024)
@@ -2223,7 +2221,7 @@ var CORE_METHODS = {
2223
2221
  }
2224
2222
  };
2225
2223
 
2226
- // ../wallet/dist/protocol-DvzlUKB8.mjs
2224
+ // ../wallet/dist/protocol-DbpLncEB.mjs
2227
2225
  var MAX_FACTOR_CHARS = 512;
2228
2226
  var MAX_STRING_BYTES = 64000;
2229
2227
  var MAX_PAYLOAD_CHARS = 1400000;
@@ -2245,15 +2243,11 @@ var backupEnvelope = obj({
2245
2243
  factors: arr(backupEnvelopeFactor, 5, 1),
2246
2244
  payload: str(MAX_PAYLOAD_CHARS)
2247
2245
  });
2248
- var backupHeader = obj({
2249
- wallets: arr(obj({
2250
- walletId: str(128),
2251
- origin: union(literal("mnemonic"), literal("passkey")),
2252
- words: union(literal(12), literal(15), literal(18), literal(21), literal(24))
2253
- }), 1000),
2254
- importedNostrKeyCount: int(0, 1e4),
2255
- importedChainKeyCount: int(0, 1e4)
2256
- });
2246
+ var backupHeader = obj({ wallets: arr(obj({
2247
+ walletId: str(128),
2248
+ origin: union(literal("mnemonic"), literal("passkey")),
2249
+ words: union(literal(12), literal(15), literal(18), literal(21), literal(24))
2250
+ }), 1000) });
2257
2251
  var backupEnvelopeText = str(MAX_ENVELOPE_CHARS);
2258
2252
  var backupInfo = obj({
2259
2253
  id: str(32, /^[0-9a-f]{32}$/),
@@ -2402,36 +2396,19 @@ var CHAINS_METHODS = {
2402
2396
  }
2403
2397
  };
2404
2398
  var hex128 = str(128, /^[0-9a-f]{128}$/);
2405
- var nostrKeyRef = union(obj({
2399
+ var nostrKeyRef = obj({
2406
2400
  kind: literal("derived"),
2407
2401
  walletId,
2408
- groupIndex
2409
- }), obj({
2410
- kind: literal("standalone"),
2411
- id: publicKey
2412
- }), obj({
2413
- kind: literal("nip46-client"),
2414
- id: publicKey
2415
- }));
2416
- var nostrKeyInfo = union(obj({
2417
- ref: nostrKeyRef,
2418
- publicKey,
2419
- origin: union(literal("nsec"), literal("ncryptsec"), literal("generated")),
2420
- backedUp: bool,
2421
- createdAt: safeTime
2422
- }), obj({
2402
+ index: identityIndex
2403
+ });
2404
+ var nostrKeyInfo = obj({
2423
2405
  ref: nostrKeyRef,
2424
2406
  publicKey,
2425
- origin: union(literal("derived"), literal("nip46-client")),
2426
2407
  createdAt: safeTime
2427
- }));
2428
- var nostrStatus = obj({ keys: arr(nostrKeyInfo, MAX_SNAPSHOT_ITEMS) });
2429
- var keyResult = obj({
2430
- key: nostrKeyInfo,
2431
- session: sessionId
2432
2408
  });
2409
+ var nostrStatus = obj({ keys: arr(nostrKeyInfo, MAX_SNAPSHOT_ITEMS) });
2433
2410
  var derivedNostrKey = obj({
2434
- groupIndex,
2411
+ index: identityIndex,
2435
2412
  publicKey
2436
2413
  });
2437
2414
  var tags = arr(arr(str(MAX_TAG_ITEM), 64), MAX_TAGS);
@@ -2459,14 +2436,6 @@ var rumor = obj({
2459
2436
  tags,
2460
2437
  content: str(MAX_TEXT)
2461
2438
  });
2462
- var nostrImportInput = union(obj({
2463
- kind: literal("nsec"),
2464
- nsec: bytes(1, 256)
2465
- }), obj({
2466
- kind: literal("ncryptsec"),
2467
- ncryptsec: str(512, /^ncryptsec1/),
2468
- password: bytes(1, 1024)
2469
- }));
2470
2439
  var nostrExportFormat = union(obj({ kind: literal("nsec") }), obj({
2471
2440
  kind: literal("ncryptsec"),
2472
2441
  password: bytes(1, 1024)
@@ -2483,7 +2452,7 @@ var NOSTR_METHODS = {
2483
2452
  presence: false,
2484
2453
  params: obj({
2485
2454
  walletId,
2486
- from: groupIndex,
2455
+ from: identityIndex,
2487
2456
  count: int(1, 20)
2488
2457
  }),
2489
2458
  result: obj({ keys: arr(derivedNostrKey, 20) })
@@ -2493,38 +2462,14 @@ var NOSTR_METHODS = {
2493
2462
  presence: false,
2494
2463
  params: obj({
2495
2464
  walletId,
2496
- groupIndex
2497
- }),
2498
- result: nostrKeyInfo
2499
- },
2500
- "nostr.importKey": {
2501
- session: false,
2502
- presence: true,
2503
- params: obj({
2504
- input: nostrImportInput,
2505
- factor: opt(factor)
2465
+ index: identityIndex
2506
2466
  }),
2507
- result: keyResult
2508
- },
2509
- "nostr.generateKey": {
2510
- session: false,
2511
- presence: true,
2512
- params: obj({ factor: opt(factor) }),
2513
- result: keyResult
2514
- },
2515
- "nostr.createNip46ClientKey": {
2516
- session: true,
2517
- presence: false,
2518
- params: nullValue,
2519
2467
  result: nostrKeyInfo
2520
2468
  },
2521
2469
  "nostr.removeKey": {
2522
2470
  session: true,
2523
2471
  presence: true,
2524
- params: obj({
2525
- publicKey,
2526
- verify: opt(factor)
2527
- }),
2472
+ params: obj({ publicKey }),
2528
2473
  result: nullValue
2529
2474
  },
2530
2475
  "nostr.exportKey": {
@@ -2578,6 +2523,39 @@ var NOSTR_METHODS = {
2578
2523
  events: arr(signedEvent, 64)
2579
2524
  }),
2580
2525
  result: obj({ results: arr(union(obj({ ok: rumor }), obj({ err: walletErrorCode })), 64) })
2526
+ },
2527
+ "nostr.syncKey": {
2528
+ session: true,
2529
+ presence: false,
2530
+ params: obj({ walletId }),
2531
+ result: obj({ publicKey })
2532
+ },
2533
+ "nostr.syncSign": {
2534
+ session: true,
2535
+ presence: false,
2536
+ params: obj({
2537
+ walletId,
2538
+ event: signEventInput
2539
+ }),
2540
+ result: signedEvent
2541
+ },
2542
+ "nostr.syncEncrypt": {
2543
+ session: true,
2544
+ presence: false,
2545
+ params: obj({
2546
+ walletId,
2547
+ text: str(MAX_TEXT)
2548
+ }),
2549
+ result: textResult
2550
+ },
2551
+ "nostr.syncDecrypt": {
2552
+ session: true,
2553
+ presence: false,
2554
+ params: obj({
2555
+ walletId,
2556
+ text: str(MAX_TEXT * 4)
2557
+ }),
2558
+ result: textResult
2581
2559
  }
2582
2560
  };
2583
2561
  var MAX_LEAVES = 256;
@@ -2763,6 +2741,27 @@ var decimalU128 = (value) => {
2763
2741
  throw new ValidationError;
2764
2742
  return value;
2765
2743
  };
2744
+ var outflowIntents = [
2745
+ obj({
2746
+ kind: literal("exit"),
2747
+ address: str(128),
2748
+ amountSats: satsAmount(),
2749
+ maxFeeSats: satsAmount()
2750
+ }),
2751
+ obj({
2752
+ kind: literal("onchain"),
2753
+ address: str(128),
2754
+ maxFeeSats: satsAmount()
2755
+ }),
2756
+ obj({
2757
+ kind: literal("token"),
2758
+ tokenIdentifier: bytes(32),
2759
+ receivers: arr(obj({
2760
+ ownerPublicKey: bytes(33),
2761
+ amount: decimalU128
2762
+ }), 256, 1)
2763
+ })
2764
+ ];
2766
2765
  var approveIntent = union(obj({
2767
2766
  kind: literal("transfer"),
2768
2767
  receivers: arr(obj({
@@ -2774,23 +2773,7 @@ var approveIntent = union(obj({
2774
2773
  invoice: str(4096),
2775
2774
  amountSats: opt(satsAmount()),
2776
2775
  maxFeeSats: satsAmount()
2777
- }), obj({
2778
- kind: literal("exit"),
2779
- address: str(128),
2780
- amountSats: satsAmount(),
2781
- maxFeeSats: satsAmount()
2782
- }), obj({
2783
- kind: literal("onchain"),
2784
- address: str(128),
2785
- maxFeeSats: satsAmount()
2786
- }), obj({
2787
- kind: literal("token"),
2788
- tokenIdentifier: bytes(32),
2789
- receivers: arr(obj({
2790
- ownerPublicKey: bytes(33),
2791
- amount: decimalU128
2792
- }), 256, 1)
2793
- }));
2776
+ }), ...outflowIntents);
2794
2777
  var approvalSummary = union(obj({
2795
2778
  kind: literal("transfer"),
2796
2779
  receivers: arr(obj({
@@ -2802,23 +2785,7 @@ var approvalSummary = union(obj({
2802
2785
  paymentHash: bytes(32),
2803
2786
  invoiceAmountSats: opt(satsAmount()),
2804
2787
  maxFeeSats: satsAmount()
2805
- }), obj({
2806
- kind: literal("exit"),
2807
- address: str(128),
2808
- amountSats: satsAmount(),
2809
- maxFeeSats: satsAmount()
2810
- }), obj({
2811
- kind: literal("onchain"),
2812
- address: str(128),
2813
- maxFeeSats: satsAmount()
2814
- }), obj({
2815
- kind: literal("token"),
2816
- tokenIdentifier: bytes(32),
2817
- receivers: arr(obj({
2818
- ownerPublicKey: bytes(33),
2819
- amount: decimalU128
2820
- }), 256, 1)
2821
- }));
2788
+ }), ...outflowIntents);
2822
2789
  var SPARK_METHODS = {
2823
2790
  "spark.identityPublicKey": {
2824
2791
  session: true,
@@ -2943,7 +2910,7 @@ var SPARK_METHODS = {
2943
2910
  result: approvalSummary
2944
2911
  }
2945
2912
  };
2946
- var PROTOCOL_VERSION = 1;
2913
+ var PROTOCOL_VERSION = 2;
2947
2914
  var UNATTRIBUTED_ID = 0;
2948
2915
  var MAX_REQUEST_BYTES = 1048576;
2949
2916
  function requestBytes(value) {
@@ -2993,7 +2960,7 @@ function isProtocolValue(value) {
2993
2960
  return Object.values(value).every(isProtocolValue);
2994
2961
  }
2995
2962
  var statusPayload = obj({
2996
- protocol: literal(1),
2963
+ protocol: literal(2),
2997
2964
  vault: union(literal("uninitialized"), literal("locked"), literal("unlocked"), literal("corrupted"), literal("unsupported"), literal("unavailable")),
2998
2965
  factors: arr(factorInfo, MAX_SNAPSHOT_ITEMS),
2999
2966
  wallets: arr(walletInfo, MAX_SNAPSHOT_ITEMS),
@@ -3018,11 +2985,11 @@ var errorPayload = obj({
3018
2985
  retryAt: opt(safeTime)
3019
2986
  });
3020
2987
  var kernelEvent = union(obj({
3021
- v: literal(1),
2988
+ v: literal(2),
3022
2989
  event: literal("status"),
3023
2990
  status: statusPayload
3024
2991
  }), obj({
3025
- v: literal(1),
2992
+ v: literal(2),
3026
2993
  event: literal("locked"),
3027
2994
  reason: lockReason
3028
2995
  }));
@@ -3956,14 +3923,8 @@ function asPublicKey(value) {
3956
3923
  }
3957
3924
  return value;
3958
3925
  }
3959
- function asGroupIndex(value) {
3960
- if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 2147483647) {
3961
- throw headerFailure();
3962
- }
3963
- return value;
3964
- }
3965
- function asBoolean(value) {
3966
- if (typeof value !== "boolean") {
3926
+ function asIdentityIndex(value) {
3927
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 2147483646) {
3967
3928
  throw headerFailure();
3968
3929
  }
3969
3930
  return value;
@@ -4277,7 +4238,7 @@ var RECORD_KIND_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
4277
4238
  function isRecordKind(kind) {
4278
4239
  return RECORD_KIND_PATTERN.test(kind);
4279
4240
  }
4280
- var VAULT_FORMAT = 2;
4241
+ var VAULT_FORMAT = 3;
4281
4242
 
4282
4243
  // ../wallet-kernel/src/vault/vault.ts
4283
4244
  var BACKOFF_MS = [30000, 60000, 300000];
@@ -6904,6 +6865,14 @@ async function seedFromMnemonic(mnemonic, passphrase, pbkdf2) {
6904
6865
  async function seedFromEntropy(entropy, pbkdf2) {
6905
6866
  return seedFromMnemonic(mnemonicFromEntropy(entropy), "", pbkdf2);
6906
6867
  }
6868
+ async function withSeed(pbkdf2, entropy, use) {
6869
+ const seed = await seedFromEntropy(entropy, pbkdf2);
6870
+ try {
6871
+ return await use(seed);
6872
+ } finally {
6873
+ wipe(seed);
6874
+ }
6875
+ }
6907
6876
 
6908
6877
  // ../wallet-kernel/src/session/session.ts
6909
6878
  function wipePendingFactor(pending) {
@@ -7077,6 +7046,14 @@ class Session {
7077
7046
  }
7078
7047
 
7079
7048
  // ../wallet-kernel/src/commands/vault.ts
7049
+ async function withWalletSeed(pbkdf2, dek, record, use) {
7050
+ const entropy = openRecord(dek, record);
7051
+ try {
7052
+ return await withSeed(pbkdf2, entropy, use);
7053
+ } finally {
7054
+ wipe(entropy);
7055
+ }
7056
+ }
7080
7057
  var EMPTY_IMAGE = { meta: undefined, records: [], factors: [] };
7081
7058
  async function unlockVault(ctx, params) {
7082
7059
  await ctx.reload();
@@ -7161,13 +7138,10 @@ async function removeFactor(ctx, params, requestSession) {
7161
7138
 
7162
7139
  // ../wallet-kernel/src/commands/wallets.ts
7163
7140
  async function deriveWalletMaterial(platform, entropy) {
7164
- const seed = await seedFromEntropy(entropy, platform.pbkdf2);
7165
- try {
7141
+ return withSeed(platform.pbkdf2, entropy, (seed) => {
7166
7142
  const master = masterKey(seed);
7167
7143
  return { master, walletId: walletIdOf(master) };
7168
- } finally {
7169
- wipe(seed);
7170
- }
7144
+ });
7171
7145
  }
7172
7146
  async function walletMaterial(platform, entropy, origin, words) {
7173
7147
  const { master, walletId } = await deriveWalletMaterial(platform, entropy);
@@ -7507,13 +7481,11 @@ function parseHeader(text) {
7507
7481
  return header;
7508
7482
  }
7509
7483
  var PAYLOAD_WALLET = 1;
7510
- var PAYLOAD_NOSTR = 2;
7511
- var PAYLOAD_CHAIN = 3;
7512
- function encodePayload(wallets, nostrSecrets) {
7513
- const size = 1 + wallets.reduce((acc, w) => acc + 3 + w.entropy.length, 0) + nostrSecrets.length * 33;
7484
+ function encodePayload(wallets) {
7485
+ const size = 1 + wallets.reduce((acc, w) => acc + 3 + w.entropy.length, 0);
7514
7486
  const out = new Uint8Array(size);
7515
7487
  let off = 0;
7516
- out[off++] = 1;
7488
+ out[off++] = 2;
7517
7489
  for (const w of wallets) {
7518
7490
  out[off++] = PAYLOAD_WALLET;
7519
7491
  out[off++] = ORIGIN_BYTE[w.origin] ?? 0;
@@ -7521,19 +7493,13 @@ function encodePayload(wallets, nostrSecrets) {
7521
7493
  out.set(w.entropy, off);
7522
7494
  off += w.entropy.length;
7523
7495
  }
7524
- for (const s of nostrSecrets) {
7525
- out[off++] = PAYLOAD_NOSTR;
7526
- out.set(s, off);
7527
- off += s.length;
7528
- }
7529
7496
  return out;
7530
7497
  }
7531
7498
  function decodePayload2(bytes) {
7532
- if (bytes.length === 0 || bytes[0] !== 1) {
7499
+ if (bytes.length === 0 || bytes[0] !== 2) {
7533
7500
  throw new KernelError("integrity", "backup: bad payload version");
7534
7501
  }
7535
7502
  const wallets = [];
7536
- const nostrSecrets = [];
7537
7503
  let off = 1;
7538
7504
  while (off < bytes.length) {
7539
7505
  const tag = bytes[off++];
@@ -7553,17 +7519,6 @@ function decodePayload2(bytes) {
7553
7519
  }
7554
7520
  wallets.push({ origin, entropy: bytes.slice(off, off + len) });
7555
7521
  off += len;
7556
- } else if (tag === PAYLOAD_NOSTR) {
7557
- if (off + 32 > bytes.length) {
7558
- throw new KernelError("integrity", "backup: truncated payload");
7559
- }
7560
- nostrSecrets.push(bytes.slice(off, off + 32));
7561
- off += 32;
7562
- } else if (tag === PAYLOAD_CHAIN) {
7563
- if (off + 33 > bytes.length) {
7564
- throw new KernelError("integrity", "backup: truncated payload");
7565
- }
7566
- off += 33;
7567
7522
  } else {
7568
7523
  throw new KernelError("integrity", "backup: unknown payload tag");
7569
7524
  }
@@ -7571,7 +7526,7 @@ function decodePayload2(bytes) {
7571
7526
  if (off !== bytes.length) {
7572
7527
  throw new KernelError("integrity", "backup: payload length mismatch");
7573
7528
  }
7574
- return { wallets, nostrSecrets };
7529
+ return { wallets };
7575
7530
  }
7576
7531
  function collectContents(ctx, dek) {
7577
7532
  const wallets = [];
@@ -7594,13 +7549,10 @@ function collectContents(ctx, dek) {
7594
7549
  throw error;
7595
7550
  }
7596
7551
  }
7597
- const nostrSecrets = ctx.modules.flatMap((module) => module.backupSecrets(ctx.image, dek));
7598
7552
  const header = JSON.stringify({
7599
- wallets: wallets.map(({ walletId, origin, words }) => ({ walletId, origin, words })),
7600
- importedNostrKeyCount: nostrSecrets.length,
7601
- importedChainKeyCount: 0
7553
+ wallets: wallets.map(({ walletId, origin, words }) => ({ walletId, origin, words }))
7602
7554
  });
7603
- return { wallets, nostrSecrets, header };
7555
+ return { wallets, header };
7604
7556
  } catch (error) {
7605
7557
  for (const wallet of wallets) {
7606
7558
  wallet.entropy.fill(0);
@@ -7612,9 +7564,6 @@ function wipeContents(contents) {
7612
7564
  for (const wallet of contents.wallets) {
7613
7565
  wallet.entropy.fill(0);
7614
7566
  }
7615
- for (const secretKey of contents.nostrSecrets) {
7616
- secretKey.fill(0);
7617
- }
7618
7567
  }
7619
7568
  var PURPOSE_PROTECTION = 2;
7620
7569
  function backupMaterialOf(result) {
@@ -7737,7 +7686,7 @@ function updateBackup(ctx, _params, requestSession) {
7737
7686
  const bek = openRecord(dek, record);
7738
7687
  const contents = collectContents(ctx, dek);
7739
7688
  try {
7740
- const plaintext = encodePayload(contents.wallets, contents.nostrSecrets);
7689
+ const plaintext = encodePayload(contents.wallets);
7741
7690
  const sealedPayload = seal(bek, plaintext, payloadContext(contents.header), "", ctx.platform.random);
7742
7691
  try {
7743
7692
  const envelope = {
@@ -7807,7 +7756,7 @@ async function restoreBackup(ctx, params, requestSession) {
7807
7756
  }
7808
7757
  const header = parseHeader(envelope.header);
7809
7758
  const decoded = decodePayload2(plaintext);
7810
- if (decoded.nostrSecrets.length !== header.importedNostrKeyCount || decoded.wallets.length !== header.wallets.length) {
7759
+ if (decoded.wallets.length !== header.wallets.length) {
7811
7760
  plaintext.fill(0);
7812
7761
  throw new KernelError("integrity", "backup: payload does not match header");
7813
7762
  }
@@ -7839,9 +7788,6 @@ async function restoreBackup(ctx, params, requestSession) {
7839
7788
  records.push(record);
7840
7789
  restored.push(walletInfoOf(material, backup, now));
7841
7790
  }
7842
- for (const module of ctx.modules) {
7843
- records.push(...module.backupRecords(ctx.platform, ctx.image, gated.dek, decoded.nostrSecrets, now));
7844
- }
7845
7791
  if (gated.uninitialized) {
7846
7792
  records.push(backupKeyRecord(ctx, gated.dek, bek, envelope.factors));
7847
7793
  }
@@ -7859,9 +7805,6 @@ async function restoreBackup(ctx, params, requestSession) {
7859
7805
  for (const wallet of decoded.wallets) {
7860
7806
  wallet.entropy.fill(0);
7861
7807
  }
7862
- for (const secretKey of decoded.nostrSecrets) {
7863
- secretKey.fill(0);
7864
- }
7865
7808
  }
7866
7809
  } finally {
7867
7810
  bek.fill(0);
@@ -8061,7 +8004,30 @@ var ChainError = class extends Error {
8061
8004
  }
8062
8005
  };
8063
8006
 
8064
- // ../wallet-chains/dist/message-DtIS0ZWB.mjs
8007
+ // ../wallet-chains/dist/account-ref-C2qrDbVT.mjs
8008
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8009
+ var isAccountRef = (value) => {
8010
+ if (!isRecord2(value) || typeof value["kind"] !== "string")
8011
+ return false;
8012
+ if (value["kind"] === "hd")
8013
+ return typeof value["walletId"] === "string" && typeof value["groupIndex"] === "number" && typeof value["template"] === "string";
8014
+ return value["kind"] === "imported" && typeof value["keyId"] === "string" && typeof value["family"] === "string";
8015
+ };
8016
+ var requestBase = (request) => {
8017
+ if (!isRecord2(request))
8018
+ throw new ChainError("invalid-request", "request must be an object");
8019
+ const { network, account } = request;
8020
+ if (typeof network !== "string")
8021
+ throw new ChainError("invalid-request", "request.network must be a string");
8022
+ if (!isAccountRef(account))
8023
+ throw new ChainError("invalid-request", "request.account must be an AccountRef");
8024
+ return {
8025
+ network,
8026
+ account
8027
+ };
8028
+ };
8029
+
8030
+ // ../wallet-chains/dist/message-DuJ5KSRT.mjs
8065
8031
  var MAINNET_BIP32 = {
8066
8032
  public: 76067358,
8067
8033
  private: 76066276
@@ -8212,15 +8178,15 @@ var signLegacyMessage = (message, privateKey) => {
8212
8178
  };
8213
8179
 
8214
8180
  // ../wallet-chains/dist/bitcoin.mjs
8215
- var isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8181
+ var isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8216
8182
  var derivationPaths = (map) => {
8217
- const entries = map instanceof Map ? [...map.values()] : Array.isArray(map) ? map : isRecord$2(map) ? Object.values(map) : [];
8183
+ const entries = map instanceof Map ? [...map.values()] : Array.isArray(map) ? map : isRecord$1(map) ? Object.values(map) : [];
8218
8184
  const paths = [];
8219
8185
  for (const entry of entries) {
8220
8186
  const value = Array.isArray(entry) ? entry[1] : entry;
8221
- if (!isRecord$2(value))
8187
+ if (!isRecord$1(value))
8222
8188
  continue;
8223
- const { path } = isRecord$2(value["der"]) ? value["der"] : value;
8189
+ const { path } = isRecord$1(value["der"]) ? value["der"] : value;
8224
8190
  if (Array.isArray(path) && path.every((p) => typeof p === "number"))
8225
8191
  paths.push(path);
8226
8192
  }
@@ -8359,26 +8325,10 @@ var decodeBitcoinPsbt = (request, ownScripts = /* @__PURE__ */ new Set) => {
8359
8325
  verifiability
8360
8326
  };
8361
8327
  };
8362
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8363
- var isAccountRef = (value) => {
8364
- if (!isRecord2(value) || typeof value["kind"] !== "string")
8365
- return false;
8366
- if (value["kind"] === "hd")
8367
- return typeof value["walletId"] === "string" && typeof value["groupIndex"] === "number" && typeof value["template"] === "string";
8368
- return value["kind"] === "imported" && typeof value["keyId"] === "string" && typeof value["family"] === "string";
8369
- };
8370
8328
  var common = (request) => {
8371
- const { network } = request;
8372
- const { account } = request;
8373
- if (typeof network !== "string")
8374
- throw new ChainError("invalid-request", "request.network must be a string");
8375
- if (!isAccountRef(account))
8376
- throw new ChainError("invalid-request", "request.account must be an AccountRef");
8377
- bitcoinNetwork(network);
8378
- return {
8379
- network,
8380
- account
8381
- };
8329
+ const base = requestBase(request);
8330
+ bitcoinNetwork(base.network);
8331
+ return base;
8382
8332
  };
8383
8333
  var messageTarget = (address, network, format) => {
8384
8334
  if (typeof address !== "string")
@@ -8448,26 +8398,6 @@ var normalizeBitcoin = (request) => {
8448
8398
  };
8449
8399
  var decodeMessageTarget = (request) => messageTarget(request.address, request.network, request.format);
8450
8400
 
8451
- // ../wallet-chains/dist/bitcoin-sign.mjs
8452
- var signBitcoinPsbt = (psbt, inputs, auxRand) => {
8453
- const tx = Transaction.fromPSBT(psbt);
8454
- for (const { index, privateKey } of inputs) {
8455
- if (privateKey.length !== 32)
8456
- throw new ChainError("invalid-request", `input ${index}: private key must be 32 bytes`);
8457
- if (!tx.signIdx(privateKey, index, undefined, auxRand(index)))
8458
- throw new ChainError("invalid-request", `input ${index}: key cannot sign`);
8459
- }
8460
- return tx.toPSBT(0);
8461
- };
8462
- var signBitcoinMessage = (request, privateKey, auxRand) => {
8463
- if (privateKey.length !== 32)
8464
- throw new ChainError("invalid-request", "private key must be 32 bytes");
8465
- if (request.format === "legacy")
8466
- return signLegacyMessage(request.message, privateKey);
8467
- const scriptPubKey = OutScript.encode(Address(bitcoinNetwork(request.network).params).decode(request.address));
8468
- return signBip322Simple(request.message, scriptPubKey, privateKey, auxRand);
8469
- };
8470
-
8471
8401
  // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/sha3.js
8472
8402
  var _0n4 = BigInt(0);
8473
8403
  var _1n4 = BigInt(1);
@@ -8691,15 +8621,15 @@ class Keccak {
8691
8621
  var genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);
8692
8622
  var keccak_256 = /* @__PURE__ */ genKeccak(1, 136, 32);
8693
8623
 
8694
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/version.js
8624
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/version.js
8695
8625
  var version = "0.1.1";
8696
8626
 
8697
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/errors.js
8627
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/errors.js
8698
8628
  function getVersion() {
8699
8629
  return version;
8700
8630
  }
8701
8631
 
8702
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Errors.js
8632
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Errors.js
8703
8633
  class BaseError extends Error {
8704
8634
  details;
8705
8635
  docs;
@@ -8779,7 +8709,7 @@ function walk(err, fn) {
8779
8709
  return fn ? null : err;
8780
8710
  }
8781
8711
 
8782
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/bytes.js
8712
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/bytes.js
8783
8713
  function assertSize(bytes, size_) {
8784
8714
  if (size(bytes) > size_)
8785
8715
  throw new SizeOverflowError({
@@ -8848,7 +8778,7 @@ function trim(value, options = {}) {
8848
8778
  return start === 0 && end === value.length ? value : value.slice(start, end);
8849
8779
  }
8850
8780
 
8851
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/codec/hex.js
8781
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/codec/hex.js
8852
8782
  var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_v, i) => i.toString(16).padStart(2, "0"));
8853
8783
  var nibbleTable = /* @__PURE__ */ (() => {
8854
8784
  const table = new Uint8Array(256).fill(255);
@@ -8936,7 +8866,7 @@ class InvalidLengthError extends BaseError {
8936
8866
  }
8937
8867
  }
8938
8868
 
8939
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/codec/int.js
8869
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/codec/int.js
8940
8870
  function bytesToBigInt(value, signed) {
8941
8871
  const len = value.length;
8942
8872
  if (len === 0)
@@ -8993,11 +8923,11 @@ class IntegerOutOfRangeError extends BaseError {
8993
8923
  }
8994
8924
  }
8995
8925
 
8996
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/codec/utf8.js
8926
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/codec/utf8.js
8997
8927
  var encoder = /* @__PURE__ */ new TextEncoder;
8998
8928
  var decoder = /* @__PURE__ */ new TextDecoder;
8999
8929
 
9000
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Json.js
8930
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Json.js
9001
8931
  var bigIntSuffix = "#__bigint";
9002
8932
  function stringify(value, replacer, space) {
9003
8933
  return JSON.stringify(value, (key, value) => {
@@ -9009,9 +8939,9 @@ function stringify(value, replacer, space) {
9009
8939
  }, space);
9010
8940
  }
9011
8941
 
9012
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Hex.js
8942
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Hex.js
9013
8943
  function assert(value, options = {}) {
9014
- const { strict = false } = options;
8944
+ const { even = false, strict = false } = options;
9015
8945
  if (typeof value !== "string")
9016
8946
  throw new InvalidHexTypeError(value);
9017
8947
  if (strict) {
@@ -9020,6 +8950,8 @@ function assert(value, options = {}) {
9020
8950
  }
9021
8951
  if (!value.startsWith("0x"))
9022
8952
  throw new InvalidHexValueError2(value);
8953
+ if (even && value.length % 2 !== 0)
8954
+ throw new InvalidLengthError2(value);
9023
8955
  }
9024
8956
  function concat2(...values) {
9025
8957
  if (values.length === 0)
@@ -9143,9 +9075,9 @@ function toBytes(hex, options = {}) {
9143
9075
  return hexToBytes4(value);
9144
9076
  }
9145
9077
  function validate2(value, options = {}) {
9146
- const { strict = false } = options;
9078
+ const { even = false, strict = false } = options;
9147
9079
  try {
9148
- assert(value, { strict });
9080
+ assert(value, { even, strict });
9149
9081
  return true;
9150
9082
  } catch {
9151
9083
  return false;
@@ -9161,6 +9093,8 @@ class InvalidHexTypeError extends BaseError {
9161
9093
  }
9162
9094
  }
9163
9095
  var InvalidHexValueError2 = InvalidHexValueError;
9096
+ var InvalidLengthError2 = InvalidLengthError;
9097
+
9164
9098
  class SizeOverflowError2 extends BaseError {
9165
9099
  name = "Hex.SizeOverflowError";
9166
9100
  constructor({ givenSize, maxSize }) {
@@ -9182,7 +9116,7 @@ class SizeExceedsPaddingSizeError2 extends BaseError {
9182
9116
  }
9183
9117
  }
9184
9118
 
9185
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/hex.js
9119
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/hex.js
9186
9120
  function assertSize2(hex, size_) {
9187
9121
  const len = hex.length - 2;
9188
9122
  const size = len + 1 >> 1;
@@ -9243,7 +9177,7 @@ function trim2(value, options = {}) {
9243
9177
  return `0x${data.slice(start, end)}`;
9244
9178
  }
9245
9179
 
9246
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Bytes.js
9180
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Bytes.js
9247
9181
  function from2(value) {
9248
9182
  if (value instanceof Uint8Array)
9249
9183
  return value;
@@ -9354,7 +9288,7 @@ class SizeExceedsPaddingSizeError extends BaseError {
9354
9288
  }
9355
9289
  }
9356
9290
 
9357
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/lru.js
9291
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/lru.js
9358
9292
  class BoundedMap extends Map {
9359
9293
  maxSize;
9360
9294
  constructor(size) {
@@ -9371,20 +9305,20 @@ class BoundedMap extends Map {
9371
9305
  }
9372
9306
  }
9373
9307
 
9374
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Caches.js
9308
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Caches.js
9375
9309
  var caches = {
9376
9310
  checksum: /* @__PURE__ */ new BoundedMap(32768)
9377
9311
  };
9378
9312
  var checksum = caches.checksum;
9379
9313
 
9380
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/engine.js
9314
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/engine.js
9381
9315
  var overrides = {};
9382
9316
 
9383
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/hash.js
9317
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/hash.js
9384
9318
  var keccak256Default = (input) => keccak_256(input);
9385
9319
  var keccak256 = (input) => (overrides.Hash?.keccak256 ?? keccak256Default)(input);
9386
9320
 
9387
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Hash.js
9321
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Hash.js
9388
9322
  function keccak2562(value, options = {}) {
9389
9323
  const isBytes = value instanceof Uint8Array;
9390
9324
  const { as = isBytes ? "Bytes" : "Hex" } = options;
@@ -9394,7 +9328,7 @@ function keccak2562(value, options = {}) {
9394
9328
  return fromBytes(bytes);
9395
9329
  }
9396
9330
 
9397
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/address.js
9331
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/address.js
9398
9332
  var length = 42;
9399
9333
  var ZERO2 = 48;
9400
9334
  var NINE = 57;
@@ -9447,7 +9381,7 @@ function lowercase(value) {
9447
9381
  return String.fromCharCode.apply(null, out);
9448
9382
  }
9449
9383
 
9450
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Address.js
9384
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Address.js
9451
9385
  function assert2(value, options = {}) {
9452
9386
  const { strict = true } = options;
9453
9387
  const kind = classify(value);
@@ -9527,7 +9461,7 @@ class InvalidChecksumError extends BaseError {
9527
9461
  }
9528
9462
  }
9529
9463
 
9530
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/regex.js
9464
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/regex.js
9531
9465
  function execTyped(regex, string) {
9532
9466
  const match = regex.exec(string);
9533
9467
  return match?.groups;
@@ -9536,7 +9470,7 @@ var bytesRegex = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/;
9536
9470
  var integerRegex = /^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;
9537
9471
  var isTupleRegex = /^\(.+?\).*?$/;
9538
9472
 
9539
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/formatAbiParameter.js
9473
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/formatAbiParameter.js
9540
9474
  var tupleRegex = /^tuple(?<array>(\[(\d*)\])*)$/;
9541
9475
  function formatAbiParameter(abiParameter) {
9542
9476
  let type = abiParameter.type;
@@ -9563,7 +9497,7 @@ function formatAbiParameter(abiParameter) {
9563
9497
  return type;
9564
9498
  }
9565
9499
 
9566
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/formatAbiParameters.js
9500
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/formatAbiParameters.js
9567
9501
  function formatAbiParameters(abiParameters) {
9568
9502
  let params = "";
9569
9503
  const length = abiParameters.length;
@@ -9576,7 +9510,7 @@ function formatAbiParameters(abiParameters) {
9576
9510
  return params;
9577
9511
  }
9578
9512
 
9579
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/errors.js
9513
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/errors.js
9580
9514
  class InvalidAbiItemError extends BaseError {
9581
9515
  name = "AbiItem.InvalidAbiItemError";
9582
9516
  constructor({ signature }) {
@@ -9711,7 +9645,7 @@ class CircularReferenceError extends BaseError {
9711
9645
  }
9712
9646
  }
9713
9647
 
9714
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/signatures.js
9648
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/signatures.js
9715
9649
  var errorSignatureRegex = /^error (?<name>[a-zA-Z$_][a-zA-Z0-9$_]*)\((?<parameters>.*?)\)$/;
9716
9650
  function isErrorSignature(signature) {
9717
9651
  return errorSignatureRegex.test(signature);
@@ -9771,7 +9705,7 @@ var functionModifiers = new Set([
9771
9705
  "storage"
9772
9706
  ]);
9773
9707
 
9774
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/cache.js
9708
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/cache.js
9775
9709
  function getParameterCacheKey(param, type, structs) {
9776
9710
  let structKey = "";
9777
9711
  if (structs)
@@ -9840,7 +9774,7 @@ var parameterCache = new Map([
9840
9774
  ]
9841
9775
  ]);
9842
9776
 
9843
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/utils.js
9777
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/utils.js
9844
9778
  function parseSignature(signature, structs = {}) {
9845
9779
  if (isFunctionSignature(signature))
9846
9780
  return parseFunctionSignature(signature, structs);
@@ -10039,7 +9973,7 @@ function isValidDataLocation(type, isArray) {
10039
9973
  return isArray || type === "bytes" || type === "string" || type === "tuple";
10040
9974
  }
10041
9975
 
10042
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/structs.js
9976
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/runtime/structs.js
10043
9977
  function parseStructs(signatures) {
10044
9978
  const shallowStructs = {};
10045
9979
  const signaturesLength = signatures.length;
@@ -10109,7 +10043,7 @@ function resolveStructs(abiParameters = [], structs = {}, ancestors = new Set) {
10109
10043
  return components;
10110
10044
  }
10111
10045
 
10112
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Solidity.js
10046
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Solidity.js
10113
10047
  var arrayRegex = /^(.*)\[([0-9]*)\]$/;
10114
10048
  var bytesRegex2 = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/;
10115
10049
  var integerRegex2 = /^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;
@@ -10210,7 +10144,7 @@ var maxUint240 = 2n ** 240n - 1n;
10210
10144
  var maxUint248 = 2n ** 248n - 1n;
10211
10145
  var maxUint256 = 2n ** 256n - 1n;
10212
10146
 
10213
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/abiParameters.js
10147
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/abiParameters.js
10214
10148
  function decodeParameter(cursor, param, options) {
10215
10149
  const { checksumAddress, staticPosition } = options;
10216
10150
  const arrayComponents = getArrayComponents(param.type);
@@ -10752,7 +10686,7 @@ function hasDynamicChild(param) {
10752
10686
  return false;
10753
10687
  }
10754
10688
 
10755
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/cursor.js
10689
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/cursor.js
10756
10690
  var staticCursor = {
10757
10691
  bytes: new Uint8Array,
10758
10692
  dataView: new DataView(new ArrayBuffer(0)),
@@ -10943,7 +10877,7 @@ class RecursiveReadLimitExceededError extends BaseError {
10943
10877
  }
10944
10878
  }
10945
10879
 
10946
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/AbiParameters.js
10880
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/AbiParameters.js
10947
10881
  function decode2(parameters, data, options = {}) {
10948
10882
  const { as = "Array", checksumAddress = true } = options;
10949
10883
  const bytes = typeof data === "string" ? fromHex(data) : data;
@@ -11119,7 +11053,7 @@ class InvalidTypeError extends BaseError {
11119
11053
  }
11120
11054
  }
11121
11055
 
11122
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/TypedData.js
11056
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/TypedData.js
11123
11057
  function assert3(value) {
11124
11058
  const { domain, message, primaryType, types } = value;
11125
11059
  const validateValue = (type, value, name) => {
@@ -11231,7 +11165,7 @@ function encodeType(value) {
11231
11165
  function extractEip712DomainTypes(domain) {
11232
11166
  return [
11233
11167
  typeof domain?.name === "string" && { name: "name", type: "string" },
11234
- domain?.version && { name: "version", type: "string" },
11168
+ typeof domain?.version === "string" && { name: "version", type: "string" },
11235
11169
  (typeof domain?.chainId === "number" || typeof domain?.chainId === "bigint") && {
11236
11170
  name: "chainId",
11237
11171
  type: "uint256"
@@ -11414,7 +11348,7 @@ function validateReference(type) {
11414
11348
  throw new InvalidStructTypeError({ type });
11415
11349
  }
11416
11350
 
11417
- // ../wallet-chains/dist/typed-data-C6XANSQF.mjs
11351
+ // ../wallet-chains/dist/typed-data-Cf1g7JVv.mjs
11418
11352
  var isEvmAddress = (value) => /^0x[0-9a-fA-F]{40}$/.test(value);
11419
11353
  function checksumEvmAddress(address) {
11420
11354
  if (!isEvmAddress(address))
@@ -11621,7 +11555,7 @@ var typedDataWarnings = (parsed) => parsed.chainIdMismatch ? [{
11621
11555
  message: "typed-data domain.chainId does not match the request network"
11622
11556
  }] : [];
11623
11557
 
11624
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/formatAbiItem.js
11558
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/formatAbiItem.js
11625
11559
  function formatAbiItem(abiItem) {
11626
11560
  if (abiItem.type === "function")
11627
11561
  return `function ${abiItem.name}(${formatAbiParameters(abiItem.inputs)})${abiItem.stateMutability && abiItem.stateMutability !== "nonpayable" ? ` ${abiItem.stateMutability}` : ""}${abiItem.outputs?.length ? ` returns (${formatAbiParameters(abiItem.outputs)})` : ""}`;
@@ -11636,7 +11570,7 @@ function formatAbiItem(abiItem) {
11636
11570
  return "receive() external payable";
11637
11571
  }
11638
11572
 
11639
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/parseAbiItem.js
11573
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/human-readable/parseAbiItem.js
11640
11574
  function parseAbiItem(signature) {
11641
11575
  let abiItem;
11642
11576
  if (typeof signature === "string")
@@ -11657,7 +11591,7 @@ function parseAbiItem(signature) {
11657
11591
  return abiItem;
11658
11592
  }
11659
11593
 
11660
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/abiItem.js
11594
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/abiItem.js
11661
11595
  function normalizeSignature(signature) {
11662
11596
  let active = true;
11663
11597
  let current = "";
@@ -11702,8 +11636,6 @@ function normalizeSignature(signature) {
11702
11636
  }
11703
11637
  var integerTypeRegex = /^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;
11704
11638
  var fixedBytesTypeRegex = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/;
11705
- var arrayTypeRegex = /[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/;
11706
- var arraySuffixStripRegex = /(\[[0-9]{0,}\])$/;
11707
11639
  function isArgOfType(arg, abiParameter) {
11708
11640
  const argType = typeof arg;
11709
11641
  const abiParameterType = abiParameter.type;
@@ -11719,16 +11651,18 @@ function isArgOfType(arg, abiParameter) {
11719
11651
  default: {
11720
11652
  if (abiParameterType === "tuple" && "components" in abiParameter)
11721
11653
  return Object.values(abiParameter.components).every((component, index) => {
11722
- return isArgOfType(Object.values(arg)[index], component);
11654
+ return argType === "object" && isArgOfType(getComponentValue(arg, component, index), component);
11723
11655
  });
11724
11656
  if (integerTypeRegex.test(abiParameterType))
11725
11657
  return argType === "number" || argType === "bigint";
11726
11658
  if (fixedBytesTypeRegex.test(abiParameterType))
11727
11659
  return argType === "string" || arg instanceof Uint8Array;
11728
- if (arrayTypeRegex.test(abiParameterType)) {
11729
- return Array.isArray(arg) && arg.every((x) => isArgOfType(x, {
11660
+ const arrayComponents = getArrayComponents(abiParameterType);
11661
+ if (arrayComponents) {
11662
+ const [length, type] = arrayComponents;
11663
+ return Array.isArray(arg) && (length === null || arg.length === length) && arg.every((x) => isArgOfType(x, {
11730
11664
  ...abiParameter,
11731
- type: abiParameterType.replace(arraySuffixStripRegex, "")
11665
+ type
11732
11666
  }));
11733
11667
  }
11734
11668
  return false;
@@ -11739,8 +11673,33 @@ function getAmbiguousTypes(sourceParameters, targetParameters, args) {
11739
11673
  for (let parameterIndex = 0;parameterIndex < sourceParameters.length; parameterIndex++) {
11740
11674
  const sourceParameter = sourceParameters[parameterIndex];
11741
11675
  const targetParameter = targetParameters[parameterIndex];
11742
- if (sourceParameter.type === "tuple" && targetParameter.type === "tuple" && "components" in sourceParameter && "components" in targetParameter)
11743
- return getAmbiguousTypes(sourceParameter.components, targetParameter.components, args[parameterIndex]);
11676
+ if (!targetParameter)
11677
+ continue;
11678
+ if (sourceParameter.type === "tuple" && targetParameter.type === "tuple" && "components" in sourceParameter && "components" in targetParameter) {
11679
+ const value = args[parameterIndex];
11680
+ const types = getAmbiguousTypes(sourceParameter.components, targetParameter.components, sourceParameter.components.map((component, index) => getComponentValue(value, component, index)));
11681
+ if (types)
11682
+ return types;
11683
+ continue;
11684
+ }
11685
+ const sourceArray = getArrayComponents(sourceParameter.type);
11686
+ const targetArray = getArrayComponents(targetParameter.type);
11687
+ if (sourceArray && targetArray) {
11688
+ const types = getAmbiguousTypes([
11689
+ {
11690
+ ...sourceParameter,
11691
+ type: sourceArray[1]
11692
+ }
11693
+ ], [
11694
+ {
11695
+ ...targetParameter,
11696
+ type: targetArray[1]
11697
+ }
11698
+ ], [args[parameterIndex]?.[0]]);
11699
+ if (types)
11700
+ return types;
11701
+ continue;
11702
+ }
11744
11703
  const sourceType = sourceParameter.type;
11745
11704
  const targetType = targetParameter.type;
11746
11705
  const arg = args[parameterIndex];
@@ -11748,14 +11707,19 @@ function getAmbiguousTypes(sourceParameters, targetParameters, args) {
11748
11707
  if (sourceType === "address" && targetType === "bytes20" || sourceType === "bytes20" && targetType === "address")
11749
11708
  ambiguous = true;
11750
11709
  else if (sourceType === "address" && targetType === "string" || sourceType === "string" && targetType === "address" || sourceType === "address" && targetType === "bytes" || sourceType === "bytes" && targetType === "address")
11751
- ambiguous = validate3(arg, { strict: false });
11710
+ ambiguous = arg === undefined || validate3(arg, { strict: false });
11752
11711
  if (ambiguous)
11753
11712
  return [sourceType, targetType];
11754
11713
  }
11755
11714
  return;
11756
11715
  }
11716
+ function getComponentValue(arg, component, index) {
11717
+ if (Array.isArray(arg))
11718
+ return arg[index];
11719
+ return arg?.[component.name];
11720
+ }
11757
11721
 
11758
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/AbiItem.js
11722
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/AbiItem.js
11759
11723
  function from3(abiItem, options = {}) {
11760
11724
  const { prepare = true } = options;
11761
11725
  const item = (() => {
@@ -11923,7 +11887,7 @@ class InvalidSelectorSizeError extends BaseError {
11923
11887
  }
11924
11888
  }
11925
11889
 
11926
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/AbiFunction.js
11890
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/AbiFunction.js
11927
11891
  function decodeData(...parameters) {
11928
11892
  const [abiFunction, data, options] = (() => {
11929
11893
  if (Array.isArray(parameters[0])) {
@@ -11985,7 +11949,7 @@ function getSelector2(abiItem) {
11985
11949
  return getSelector(abiItem);
11986
11950
  }
11987
11951
 
11988
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/PersonalMessage.js
11952
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/PersonalMessage.js
11989
11953
  var erc191PrefixHex = "0x19" + fromString(`Ethereum Signed Message:
11990
11954
  `).slice(2);
11991
11955
  function encode3(data) {
@@ -11996,7 +11960,7 @@ function getSignPayload2(data) {
11996
11960
  return keccak2562(encode3(data));
11997
11961
  }
11998
11962
 
11999
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Signature.js
11963
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Signature.js
12000
11964
  function assert4(signature, options = {}) {
12001
11965
  const { recovered } = options;
12002
11966
  if (typeof signature.r === "undefined")
@@ -12120,8 +12084,8 @@ function fromRecoveredBytes(bytes) {
12120
12084
  }
12121
12085
  function toHex(signature) {
12122
12086
  assert4(signature);
12123
- const r = signature.r;
12124
- const s = signature.s;
12087
+ const r = padLeft(signature.r, 32);
12088
+ const s = padLeft(signature.s, 32);
12125
12089
  const signature_ = concat2(r, s, typeof signature.yParity === "number" ? fromNumber(yParityToV(signature.yParity), { size: 1 }) : "0x");
12126
12090
  return signature_;
12127
12091
  }
@@ -12193,7 +12157,7 @@ class InvalidVError extends BaseError {
12193
12157
  }
12194
12158
  }
12195
12159
 
12196
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/cryptoIo.js
12160
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/cryptoIo.js
12197
12161
  function formatSignature(signature, as) {
12198
12162
  if (as === "Hex")
12199
12163
  return toHex(signature);
@@ -12202,7 +12166,7 @@ function formatSignature(signature, as) {
12202
12166
  return signature;
12203
12167
  }
12204
12168
 
12205
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/secp256k1.js
12169
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/secp256k1.js
12206
12170
  var signDefault = (payload, privateKey, options) => secp256k1.sign(payload, privateKey, {
12207
12171
  ...options,
12208
12172
  format: "recovered",
@@ -12210,9 +12174,9 @@ var signDefault = (payload, privateKey, options) => secp256k1.sign(payload, priv
12210
12174
  });
12211
12175
  var sign = (payload, privateKey, options) => (overrides.Secp256k1?.sign ?? signDefault)(payload, privateKey, options);
12212
12176
 
12213
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/entropy.js
12177
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/entropy.js
12214
12178
  var extraEntropy = false;
12215
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Secp256k1.js
12179
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Secp256k1.js
12216
12180
  function sign2(options) {
12217
12181
  const { as = "Object", extraEntropy: extraEntropy2 = extraEntropy, hash, payload, privateKey } = options;
12218
12182
  const sigBytes = sign(from2(payload), from2(privateKey), {
@@ -12225,7 +12189,7 @@ function sign2(options) {
12225
12189
  var fromPrfDomain = fromString2("ox.secp256k1.fromPrf.v1");
12226
12190
  var fromSeedDomain = fromString2("ox.secp256k1.fromSeed.v1");
12227
12191
 
12228
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/AccessList.js
12192
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/AccessList.js
12229
12193
  function toTupleList(accessList) {
12230
12194
  if (!accessList || accessList.length === 0)
12231
12195
  return [];
@@ -12250,7 +12214,7 @@ class InvalidStorageKeySizeError extends BaseError {
12250
12214
  }
12251
12215
  }
12252
12216
 
12253
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/internal/tx.js
12217
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/internal/tx.js
12254
12218
  function quantityToHex(value) {
12255
12219
  if (value === undefined || value === null)
12256
12220
  return "0x";
@@ -12259,7 +12223,7 @@ function quantityToHex(value) {
12259
12223
  return fromNumber(value);
12260
12224
  }
12261
12225
 
12262
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Rlp.js
12226
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Rlp.js
12263
12227
  function from6(value, options) {
12264
12228
  const { as } = options;
12265
12229
  const ctx = { lengths: [], cursor: 0 };
@@ -12502,7 +12466,7 @@ function invalidNibble(hex) {
12502
12466
  return new BaseError(`Invalid hex string \`${hex}\`.`);
12503
12467
  }
12504
12468
 
12505
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelopeEip2930.js
12469
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelopeEip2930.js
12506
12470
  function assert5(envelope) {
12507
12471
  const { chainId, gasPrice, to } = envelope;
12508
12472
  if (chainId <= 0)
@@ -12546,7 +12510,7 @@ function serialize(envelope, options = {}) {
12546
12510
  return concat2("0x01", fromHex3(serialized));
12547
12511
  }
12548
12512
 
12549
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelopeLegacy.js
12513
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelopeLegacy.js
12550
12514
  function assert6(envelope) {
12551
12515
  const { chainId, gasPrice, to } = envelope;
12552
12516
  if (to)
@@ -12623,7 +12587,7 @@ function serialize2(envelope, options = {}) {
12623
12587
  return fromHex3(serialized);
12624
12588
  }
12625
12589
 
12626
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/Value.js
12590
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/Value.js
12627
12591
  var exponents = {
12628
12592
  wei: 0,
12629
12593
  gwei: 9,
@@ -12656,7 +12620,7 @@ class InvalidDecimalsError extends BaseError {
12656
12620
  }
12657
12621
  }
12658
12622
 
12659
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelope.js
12623
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelope.js
12660
12624
  class FeeCapTooHighError extends BaseError {
12661
12625
  name = "TransactionEnvelope.FeeCapTooHighError";
12662
12626
  constructor({ feeCap } = {}) {
@@ -12687,7 +12651,7 @@ class TipAboveFeeCapError extends BaseError {
12687
12651
  }
12688
12652
  }
12689
12653
 
12690
- // ../../node_modules/.bun/ox@1.8.9+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelopeEip1559.js
12654
+ // ../../node_modules/.bun/ox@1.8.12+ff0372d108591aba/node_modules/ox/dist/core/TxEnvelopeEip1559.js
12691
12655
  var serializedType = "0x02";
12692
12656
  function assert7(envelope) {
12693
12657
  const { chainId, maxPriorityFeePerGas, maxFeePerGas, to } = envelope;
@@ -12959,24 +12923,10 @@ var decodeEvm = (request, table = evmTokenTable) => {
12959
12923
  verifiability: "opaque"
12960
12924
  };
12961
12925
  };
12962
- var isAccountRef2 = (value) => {
12963
- if (!isRecord3(value) || typeof value["kind"] !== "string")
12964
- return false;
12965
- if (value["kind"] === "hd")
12966
- return typeof value["walletId"] === "string" && typeof value["groupIndex"] === "number" && typeof value["template"] === "string";
12967
- if (value["kind"] === "imported")
12968
- return typeof value["keyId"] === "string" && typeof value["family"] === "string";
12969
- return false;
12970
- };
12971
12926
  var normalizeEvm = (request) => {
12972
12927
  if (!isRecord3(request) || typeof request["kind"] !== "string")
12973
12928
  throw new ChainError("invalid-request", "request must be an object with a kind");
12974
- const { network } = request;
12975
- const { account } = request;
12976
- if (typeof network !== "string")
12977
- throw new ChainError("invalid-request", "request.network must be a string");
12978
- if (!isAccountRef2(account))
12979
- throw new ChainError("invalid-request", "request.account must be an AccountRef");
12929
+ const { network, account } = requestBase(request);
12980
12930
  const chainId = networkChainId(network);
12981
12931
  if (request["kind"] === "evm.transaction") {
12982
12932
  const tx = normalizeEvmTransaction(request["tx"]);
@@ -13015,79 +12965,6 @@ var normalizeEvm = (request) => {
13015
12965
  throw new ChainError("unsupported", `unsupported sign request kind: ${request["kind"]}`);
13016
12966
  };
13017
12967
 
13018
- // ../wallet-chains/dist/evm-sign.mjs
13019
- function assertHex2(value, field) {
13020
- if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(value))
13021
- throw new ChainError("invalid-quantity", `${field} must be 0x-prefixed bytes`);
13022
- }
13023
- var hex = (value, field) => {
13024
- assertHex2(value, field);
13025
- return value;
13026
- };
13027
- var key = (privateKey) => {
13028
- if (privateKey.length !== 32)
13029
- throw new ChainError("invalid-request", "private key must be 32 bytes");
13030
- return fromBytes(privateKey);
13031
- };
13032
- var accessEntry = (entry) => ({
13033
- address: hex(entry.address, "accessList.address"),
13034
- storageKeys: entry.storageKeys.map((k) => hex(k, "accessList.storageKeys"))
13035
- });
13036
- var sign3 = (payload, privateKey) => sign2({
13037
- payload,
13038
- privateKey,
13039
- as: "Object"
13040
- });
13041
- var signEvmTransaction = (tx, privateKey) => {
13042
- const privateKeyHex = key(privateKey);
13043
- const base = {
13044
- chainId: tx.chainId,
13045
- to: tx.to === undefined ? undefined : hex(tx.to, "to"),
13046
- data: hex(tx.data, "data"),
13047
- value: BigInt(tx.value),
13048
- nonce: BigInt(tx.nonce),
13049
- gas: BigInt(tx.gas)
13050
- };
13051
- if (tx.type === "legacy") {
13052
- const envelope = {
13053
- ...base,
13054
- type: "legacy",
13055
- gasPrice: BigInt(tx.gasPrice)
13056
- };
13057
- const signature = sign3(getSignPayload4(envelope), privateKeyHex);
13058
- return toBytes(serialize2(envelope, { signature }));
13059
- }
13060
- if (tx.type === "eip2930") {
13061
- const envelope = {
13062
- ...base,
13063
- type: "eip2930",
13064
- gasPrice: BigInt(tx.gasPrice),
13065
- accessList: tx.accessList.map(accessEntry)
13066
- };
13067
- const signature = sign3(getSignPayload3(envelope), privateKeyHex);
13068
- return toBytes(serialize(envelope, { signature }));
13069
- }
13070
- const envelope = {
13071
- ...base,
13072
- type: "eip1559",
13073
- accessList: tx.accessList.map(accessEntry),
13074
- maxFeePerGas: BigInt(tx.maxFeePerGas),
13075
- maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas)
13076
- };
13077
- const signature = sign3(getSignPayload5(envelope), privateKeyHex);
13078
- return toBytes(serialize3(envelope, { signature }));
13079
- };
13080
- var rs_v = (signature) => toBytes2(signature);
13081
- var signEvmPersonalMessage = (message, privateKey) => {
13082
- const payload = getSignPayload2(fromBytes(message));
13083
- return rs_v(from5(sign3(payload, key(privateKey))));
13084
- };
13085
- var signEvmTypedData = (typedData, privateKey) => {
13086
- const { json } = parseTypedData(typedData, "eip155:1");
13087
- const payload = getSignPayload(json);
13088
- return rs_v(from5(sign3(payload, key(privateKey))));
13089
- };
13090
-
13091
12968
  // ../../node_modules/.bun/@solana+errors@8.5.0+ff0372d108591aba/node_modules/@solana/errors/dist/index.browser.mjs
13092
12969
  var SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED = 1;
13093
12970
  var SOLANA_ERROR__INVALID_NONCE = 2;
@@ -14562,14 +14439,14 @@ var parseCompiledMessage = (bytes) => {
14562
14439
  lookupAddresses: lookups.map((l) => l.lookupTableAddress)
14563
14440
  };
14564
14441
  };
14565
- var isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14442
+ var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14566
14443
  var isStringArray = (value) => Array.isArray(value) && value.every((v) => typeof v === "string");
14567
14444
  var isNumberArray = (value) => Array.isArray(value) && value.every((v) => typeof v === "number");
14568
- var isArrayLike = (value) => isRecord$1(value) && typeof value["length"] === "number";
14569
- var isIx = (value) => isRecord$1(value) && typeof value["programAddressIndex"] === "number" && (value["accountIndices"] === undefined || isNumberArray(value["accountIndices"]) || isArrayLike(value["accountIndices"])) && value["data"] instanceof Uint8Array;
14570
- var isLookup = (value) => isRecord$1(value) && typeof value["lookupTableAddress"] === "string" && (isNumberArray(value["readonlyIndexes"]) || value["readonlyIndexes"] instanceof Uint8Array) && (isNumberArray(value["writableIndexes"]) || value["writableIndexes"] instanceof Uint8Array);
14445
+ var isArrayLike = (value) => isRecord4(value) && typeof value["length"] === "number";
14446
+ var isIx = (value) => isRecord4(value) && typeof value["programAddressIndex"] === "number" && (value["accountIndices"] === undefined || isNumberArray(value["accountIndices"]) || isArrayLike(value["accountIndices"])) && value["data"] instanceof Uint8Array;
14447
+ var isLookup = (value) => isRecord4(value) && typeof value["lookupTableAddress"] === "string" && (isNumberArray(value["readonlyIndexes"]) || value["readonlyIndexes"] instanceof Uint8Array) && (isNumberArray(value["writableIndexes"]) || value["writableIndexes"] instanceof Uint8Array);
14571
14448
  var asCompiledMessage = (value) => {
14572
- if (!isRecord$1(value) || !isRecord$1(value["header"]))
14449
+ if (!isRecord4(value) || !isRecord4(value["header"]))
14573
14450
  throw new ChainError("invalid-request", "compiled message failed to decode");
14574
14451
  const { header } = value;
14575
14452
  const { staticAccounts } = value;
@@ -14790,14 +14667,6 @@ var decodeTransaction2 = (request, signer, table) => {
14790
14667
  };
14791
14668
  };
14792
14669
  var decodeSolana = (request, signer, table = solanaTokenTable) => decodeTransaction2(request, signer, table);
14793
- var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14794
- var isAccountRef3 = (value) => {
14795
- if (!isRecord4(value) || typeof value["kind"] !== "string")
14796
- return false;
14797
- if (value["kind"] === "hd")
14798
- return typeof value["walletId"] === "string" && typeof value["groupIndex"] === "number" && typeof value["template"] === "string";
14799
- return value["kind"] === "imported" && typeof value["keyId"] === "string" && typeof value["family"] === "string";
14800
- };
14801
14670
  var solanaNetwork = (network) => {
14802
14671
  if (!SOLANA_NETWORKS.includes(network))
14803
14672
  throw new ChainError("unsupported", `unknown Solana network: ${network}`);
@@ -14808,7 +14677,7 @@ var validateLookupTablesRaw = (tables) => {
14808
14677
  if (!Array.isArray(tables))
14809
14678
  throw new ChainError("unknown-field", "lookupTables must be an array");
14810
14679
  const parsed = tables.map((t) => {
14811
- if (!isRecord4(t) || typeof t["address"] !== "string" || !Array.isArray(t["addresses"]))
14680
+ if (!isRecord2(t) || typeof t["address"] !== "string" || !Array.isArray(t["addresses"]))
14812
14681
  throw new ChainError("unknown-field", "lookupTables entries must be { address, addresses }");
14813
14682
  const addresses = t["addresses"].map((a) => {
14814
14683
  if (typeof a !== "string")
@@ -14824,14 +14693,9 @@ var validateLookupTablesRaw = (tables) => {
14824
14693
  return parsed;
14825
14694
  };
14826
14695
  var normalizeSolana = (request, signer) => {
14827
- if (!isRecord4(request) || typeof request["kind"] !== "string")
14696
+ if (!isRecord2(request) || typeof request["kind"] !== "string")
14828
14697
  throw new ChainError("invalid-request", "request must be an object with a kind");
14829
- const { network } = request;
14830
- const { account } = request;
14831
- if (typeof network !== "string")
14832
- throw new ChainError("invalid-request", "request.network must be a string");
14833
- if (!isAccountRef3(account))
14834
- throw new ChainError("invalid-request", "request.account must be an AccountRef");
14698
+ const { network, account } = requestBase(request);
14835
14699
  solanaNetwork(network);
14836
14700
  if (!isSolanaAddress(signer))
14837
14701
  throw new ChainError("invalid-address", "signer is not a base58 address");
@@ -14877,16 +14741,24 @@ var normalizeSolana = (request, signer) => {
14877
14741
  throw new ChainError("unsupported", `unsupported sign request kind: ${request["kind"]}`);
14878
14742
  };
14879
14743
 
14880
- // ../wallet-chains/dist/solana-sign.mjs
14881
- var signSolanaMessage = (message, privateKey) => {
14744
+ // ../wallet-chains/dist/bitcoin-sign.mjs
14745
+ var signBitcoinPsbt = (psbt, inputs, auxRand) => {
14746
+ const tx = Transaction.fromPSBT(psbt);
14747
+ for (const { index, privateKey } of inputs) {
14748
+ if (privateKey.length !== 32)
14749
+ throw new ChainError("invalid-request", `input ${index}: private key must be 32 bytes`);
14750
+ if (!tx.signIdx(privateKey, index, undefined, auxRand(index)))
14751
+ throw new ChainError("invalid-request", `input ${index}: key cannot sign`);
14752
+ }
14753
+ return tx.toPSBT(0);
14754
+ };
14755
+ var signBitcoinMessage = (request, privateKey, auxRand) => {
14882
14756
  if (privateKey.length !== 32)
14883
- throw new ChainError("invalid-request", "private key must be a 32-byte seed");
14884
- if (message.length === 0)
14885
- throw new ChainError("invalid-request", "message must not be empty");
14886
- const signature = ed25519.sign(message, privateKey);
14887
- if (signature.length !== 64)
14888
- throw new ChainError("invalid-request", "ed25519 produced a malformed signature");
14889
- return signature;
14757
+ throw new ChainError("invalid-request", "private key must be 32 bytes");
14758
+ if (request.format === "legacy")
14759
+ return signLegacyMessage(request.message, privateKey);
14760
+ const scriptPubKey = OutScript.encode(Address(bitcoinNetwork(request.network).params).decode(request.address));
14761
+ return signBip322Simple(request.message, scriptPubKey, privateKey, auxRand);
14890
14762
  };
14891
14763
 
14892
14764
  // ../wallet-kernel/src/modules/chains/prompt.ts
@@ -14953,15 +14825,407 @@ function chainPrompt(locale, intent) {
14953
14825
  return { title, description: joinLines(lines.length === 0 ? [catalog.generic] : lines) };
14954
14826
  }
14955
14827
 
14956
- // ../wallet-kernel/src/modules/chains/index.ts
14828
+ // ../wallet-kernel/src/modules/chains/shared.ts
14957
14829
  var BTC_PURPOSE = {
14958
14830
  "btc.bip44": 44,
14959
14831
  "btc.bip49": 49,
14960
14832
  "btc.bip84": 84,
14961
14833
  "btc.bip86": 86
14962
14834
  };
14835
+ var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array);
14836
+ var deepEqual = (a, b) => {
14837
+ if (a === b) {
14838
+ return true;
14839
+ }
14840
+ if (a instanceof Uint8Array || b instanceof Uint8Array) {
14841
+ return a instanceof Uint8Array && b instanceof Uint8Array && a.length === b.length && a.every((byte, i) => byte === b[i]);
14842
+ }
14843
+ if (Array.isArray(a) || Array.isArray(b)) {
14844
+ return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
14845
+ }
14846
+ if (!isObj(a) || !isObj(b)) {
14847
+ return false;
14848
+ }
14849
+ const ka = Object.keys(a);
14850
+ const kb = new Set(Object.keys(b));
14851
+ return ka.length === kb.size && ka.every((k) => kb.has(k) && deepEqual(a[k], b[k]));
14852
+ };
14853
+ function mapChainError(error) {
14854
+ if (error instanceof ChainError) {
14855
+ throw new KernelError("invalid-input", "invalid sign request");
14856
+ }
14857
+ throw error;
14858
+ }
14859
+
14860
+ // ../wallet-kernel/src/modules/chains/bitcoin.ts
14963
14861
  var isPath = (path) => Array.isArray(path) && path.every((p) => typeof p === "number");
14964
- var hex2 = (bytes) => bytes.reduce((acc, b) => acc + b.toString(16).padStart(2, "0"), "");
14862
+ var hex = (bytes) => bytes.reduce((acc, b) => acc + b.toString(16).padStart(2, "0"), "");
14863
+ var derivationOf = (owner, fingerprint, purpose) => {
14864
+ if (purpose === 86) {
14865
+ const claimed = (der) => der.fingerprint === fingerprint && isPath(der.path);
14866
+ for (const [key, value] of owner.tapBip32Derivation ?? []) {
14867
+ if (claimed(value.der)) {
14868
+ return { pubkey: key, fingerprint: value.der.fingerprint, path: value.der.path };
14869
+ }
14870
+ }
14871
+ return;
14872
+ }
14873
+ for (const [key, value] of owner.bip32Derivation ?? []) {
14874
+ if (value.fingerprint === fingerprint) {
14875
+ return { pubkey: key, fingerprint: value.fingerprint, path: value.path };
14876
+ }
14877
+ }
14878
+ return;
14879
+ };
14880
+ var expectedPub = (purpose, pub) => purpose === 86 ? pub.slice(1) : pub;
14881
+ var expectedScript = (purpose, pub) => purpose === 86 ? p2tr(pub.slice(1)).script : purpose === 49 ? p2sh(p2wpkh(pub)).script : purpose === 44 ? p2pkh(pub).script : p2wpkh(pub).script;
14882
+ var childAt = (b, path) => {
14883
+ const [purposePath, coinPath, groupPath, change, index] = path;
14884
+ if (path.length !== 5 || purposePath !== b.purpose + b.hardened || coinPath !== b.coinType + b.hardened || groupPath !== b.account.groupIndex + b.hardened || change === undefined || index === undefined || change !== 0 && change !== 1 || index < 0 || index >= b.hardened) {
14885
+ throw new KernelError("invalid-input", "derivation path is not this account's");
14886
+ }
14887
+ const child = b.accountNode.deriveChild(change).deriveChild(index);
14888
+ b.children.push(child);
14889
+ return child;
14890
+ };
14891
+ var bitcoinInput = (b, tx, idx) => {
14892
+ const input = tx.getInput(idx);
14893
+ const entry = derivationOf(input, b.master.fingerprint, b.purpose);
14894
+ if (entry === undefined) {
14895
+ throw new KernelError("invalid-input", `input ${idx}: derivation entry is not this account's`);
14896
+ }
14897
+ const child = childAt(b, entry.path);
14898
+ const pub = child.publicKey;
14899
+ const priv = child.privateKey;
14900
+ if (pub === null || priv === null) {
14901
+ throw new KernelError("integrity", "no key at derivation path");
14902
+ }
14903
+ if (!deepEqual(entry.pubkey, expectedPub(b.purpose, pub))) {
14904
+ throw new KernelError("invalid-input", `input ${idx}: derivation pubkey is not ours`);
14905
+ }
14906
+ if (b.purpose === 44) {
14907
+ if (input.nonWitnessUtxo === undefined) {
14908
+ throw new KernelError("invalid-input", `input ${idx}: P2PKH spend requires nonWitnessUtxo`);
14909
+ }
14910
+ const vout = input.index;
14911
+ const outs = input.nonWitnessUtxo.outputs;
14912
+ const prevScript = vout === undefined ? undefined : outs[vout]?.script;
14913
+ if (prevScript === undefined || !deepEqual(prevScript, expectedScript(b.purpose, pub))) {
14914
+ throw new KernelError("invalid-input", `input ${idx}: nonWitnessUtxo prevout is not this key's`);
14915
+ }
14916
+ } else {
14917
+ const prevout = input.witnessUtxo;
14918
+ if (prevout === undefined || !deepEqual(prevout.script, expectedScript(b.purpose, pub))) {
14919
+ throw new KernelError("invalid-input", `input ${idx}: prevout script is not this key's`);
14920
+ }
14921
+ if (b.purpose === 49 && (input.redeemScript === undefined || !deepEqual(input.redeemScript, p2wpkh(pub).script))) {
14922
+ throw new KernelError("invalid-input", `input ${idx}: redeemScript is not this key's`);
14923
+ }
14924
+ }
14925
+ return { index: idx, privateKey: priv };
14926
+ };
14927
+ var bitcoinOwnScripts = (b, tx) => {
14928
+ const ownScripts = new Set;
14929
+ for (let i = 0;i < tx.outputsLength; i++) {
14930
+ const output = tx.getOutput(i);
14931
+ if (output.script === undefined) {
14932
+ continue;
14933
+ }
14934
+ const entry = derivationOf(output, b.master.fingerprint, b.purpose);
14935
+ if (entry === undefined) {
14936
+ continue;
14937
+ }
14938
+ try {
14939
+ const child = childAt(b, entry.path);
14940
+ const pub = child.publicKey;
14941
+ if (pub !== null && deepEqual(output.script, expectedScript(b.purpose, pub))) {
14942
+ ownScripts.add(hex(output.script));
14943
+ }
14944
+ } catch {
14945
+ continue;
14946
+ }
14947
+ }
14948
+ return ownScripts;
14949
+ };
14950
+ var executeBitcoinPsbt = (b, request, random, intentOnly) => {
14951
+ const tx = Transaction.fromPSBT(request.psbt);
14952
+ const inputs = request.sign.map((idx) => bitcoinInput(b, tx, idx));
14953
+ const ownScripts = bitcoinOwnScripts(b, tx);
14954
+ let normalized;
14955
+ try {
14956
+ normalized = normalizeBitcoin(request);
14957
+ } catch (error) {
14958
+ mapChainError(error);
14959
+ }
14960
+ if (!deepEqual(normalized, request)) {
14961
+ throw new KernelError("invalid-input", "request is not normalized");
14962
+ }
14963
+ let intent;
14964
+ try {
14965
+ intent = decodeBitcoinPsbt(request, ownScripts);
14966
+ } catch (error) {
14967
+ mapChainError(error);
14968
+ }
14969
+ if (intentOnly) {
14970
+ return { prompt: intent };
14971
+ }
14972
+ return {
14973
+ kind: "bitcoin.psbt",
14974
+ signedPsbt: signBitcoinPsbt(request.psbt, inputs, () => random(32))
14975
+ };
14976
+ };
14977
+ var executeBitcoinMessage = (b, request, random, intentOnly) => {
14978
+ if (request.format === "legacy" && b.account.template !== "btc.bip44") {
14979
+ throw new KernelError("unsupported", "legacy message format is btc.bip44-only");
14980
+ }
14981
+ const child = childAt(b, [
14982
+ b.purpose + b.hardened,
14983
+ b.coinType + b.hardened,
14984
+ b.account.groupIndex + b.hardened,
14985
+ request.change,
14986
+ request.index
14987
+ ]);
14988
+ const pub = child.publicKey;
14989
+ const priv = child.privateKey;
14990
+ if (pub === null || priv === null) {
14991
+ throw new KernelError("integrity", "no key at derivation path");
14992
+ }
14993
+ const derived = b.purpose === 86 ? p2tr(pub.slice(1), undefined, b.net.params).address : b.purpose === 49 ? p2sh(p2wpkh(pub, b.net.params), b.net.params).address : b.purpose === 44 ? p2pkh(pub, b.net.params).address : p2wpkh(pub, b.net.params).address;
14994
+ if (derived !== request.address) {
14995
+ throw new KernelError("invalid-input", "address is not ours");
14996
+ }
14997
+ let normalized;
14998
+ try {
14999
+ normalized = normalizeBitcoin(request);
15000
+ } catch (error) {
15001
+ mapChainError(error);
15002
+ }
15003
+ if (!deepEqual(normalized, request)) {
15004
+ throw new KernelError("invalid-input", "request is not normalized");
15005
+ }
15006
+ try {
15007
+ decodeMessageTarget(request);
15008
+ } catch (error) {
15009
+ mapChainError(error);
15010
+ }
15011
+ if (intentOnly) {
15012
+ return { prompt: MESSAGE_INTENT };
15013
+ }
15014
+ return {
15015
+ kind: "bitcoin.message",
15016
+ signature: signBitcoinMessage(request, priv, () => random(32))
15017
+ };
15018
+ };
15019
+ var executeBitcoin = (random, request, account, seed, intentOnly) => {
15020
+ const net = bitcoinNetwork(request.network);
15021
+ const master = HDKey.fromMasterSeed(seed, net.bip32);
15022
+ try {
15023
+ const purpose = BTC_PURPOSE[account.template] ?? 84;
15024
+ const { coinType } = net;
15025
+ const hardened = 2147483648;
15026
+ const accountNode = master.derive(`m/${purpose}'/${coinType}'/${account.groupIndex}'`);
15027
+ const children = [];
15028
+ const b = {
15029
+ master,
15030
+ accountNode,
15031
+ children,
15032
+ purpose,
15033
+ coinType,
15034
+ hardened,
15035
+ account,
15036
+ net
15037
+ };
15038
+ try {
15039
+ if (request.kind === "bitcoin.psbt") {
15040
+ return executeBitcoinPsbt(b, request, random, intentOnly);
15041
+ }
15042
+ return executeBitcoinMessage(b, request, random, intentOnly);
15043
+ } finally {
15044
+ for (const child of children) {
15045
+ child.wipePrivateData();
15046
+ }
15047
+ accountNode.wipePrivateData();
15048
+ }
15049
+ } finally {
15050
+ master.wipePrivateData();
15051
+ }
15052
+ };
15053
+
15054
+ // ../wallet-chains/dist/evm-sign.mjs
15055
+ function assertHex2(value, field) {
15056
+ if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(value))
15057
+ throw new ChainError("invalid-quantity", `${field} must be 0x-prefixed bytes`);
15058
+ }
15059
+ var hex2 = (value, field) => {
15060
+ assertHex2(value, field);
15061
+ return value;
15062
+ };
15063
+ var key = (privateKey) => {
15064
+ if (privateKey.length !== 32)
15065
+ throw new ChainError("invalid-request", "private key must be 32 bytes");
15066
+ return fromBytes(privateKey);
15067
+ };
15068
+ var accessEntry = (entry) => ({
15069
+ address: hex2(entry.address, "accessList.address"),
15070
+ storageKeys: entry.storageKeys.map((k) => hex2(k, "accessList.storageKeys"))
15071
+ });
15072
+ var sign3 = (payload, privateKey) => sign2({
15073
+ payload,
15074
+ privateKey,
15075
+ as: "Object"
15076
+ });
15077
+ var signEvmTransaction = (tx, privateKey) => {
15078
+ const privateKeyHex = key(privateKey);
15079
+ const base = {
15080
+ chainId: tx.chainId,
15081
+ to: tx.to === undefined ? undefined : hex2(tx.to, "to"),
15082
+ data: hex2(tx.data, "data"),
15083
+ value: BigInt(tx.value),
15084
+ nonce: BigInt(tx.nonce),
15085
+ gas: BigInt(tx.gas)
15086
+ };
15087
+ if (tx.type === "legacy") {
15088
+ const envelope = {
15089
+ ...base,
15090
+ type: "legacy",
15091
+ gasPrice: BigInt(tx.gasPrice)
15092
+ };
15093
+ const signature = sign3(getSignPayload4(envelope), privateKeyHex);
15094
+ return toBytes(serialize2(envelope, { signature }));
15095
+ }
15096
+ if (tx.type === "eip2930") {
15097
+ const envelope = {
15098
+ ...base,
15099
+ type: "eip2930",
15100
+ gasPrice: BigInt(tx.gasPrice),
15101
+ accessList: tx.accessList.map(accessEntry)
15102
+ };
15103
+ const signature = sign3(getSignPayload3(envelope), privateKeyHex);
15104
+ return toBytes(serialize(envelope, { signature }));
15105
+ }
15106
+ const envelope = {
15107
+ ...base,
15108
+ type: "eip1559",
15109
+ accessList: tx.accessList.map(accessEntry),
15110
+ maxFeePerGas: BigInt(tx.maxFeePerGas),
15111
+ maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas)
15112
+ };
15113
+ const signature = sign3(getSignPayload5(envelope), privateKeyHex);
15114
+ return toBytes(serialize3(envelope, { signature }));
15115
+ };
15116
+ var rs_v = (signature) => toBytes2(signature);
15117
+ var signEvmPersonalMessage = (message, privateKey) => {
15118
+ const payload = getSignPayload2(fromBytes(message));
15119
+ return rs_v(from5(sign3(payload, key(privateKey))));
15120
+ };
15121
+ var signEvmTypedData = (typedData, privateKey) => {
15122
+ const { json } = parseTypedData(typedData, "eip155:1");
15123
+ const payload = getSignPayload(json);
15124
+ return rs_v(from5(sign3(payload, key(privateKey))));
15125
+ };
15126
+
15127
+ // ../wallet-kernel/src/modules/chains/evm.ts
15128
+ var executeEvm = (request, account, seed, intentOnly) => {
15129
+ const master = HDKey.fromMasterSeed(seed);
15130
+ try {
15131
+ const child = master.derive(`m/44'/60'/0'/0/${account.groupIndex}`);
15132
+ try {
15133
+ const priv = child.privateKey;
15134
+ if (priv === null) {
15135
+ throw new KernelError("integrity", "no private key at account path");
15136
+ }
15137
+ let normalized;
15138
+ try {
15139
+ normalized = normalizeEvm(request);
15140
+ } catch (error) {
15141
+ mapChainError(error);
15142
+ }
15143
+ if (!deepEqual(normalized, request)) {
15144
+ throw new KernelError("invalid-input", "request is not normalized");
15145
+ }
15146
+ let intent;
15147
+ try {
15148
+ intent = decodeEvm(request);
15149
+ } catch (error) {
15150
+ mapChainError(error);
15151
+ }
15152
+ if (intentOnly) {
15153
+ return { prompt: intent };
15154
+ }
15155
+ if (request.kind === "evm.transaction") {
15156
+ return {
15157
+ kind: "evm.transaction",
15158
+ signedTransaction: signEvmTransaction(request.tx, priv)
15159
+ };
15160
+ }
15161
+ if (request.kind === "evm.personal-message") {
15162
+ return {
15163
+ kind: "evm.personal-message",
15164
+ signature: signEvmPersonalMessage(request.message, priv)
15165
+ };
15166
+ }
15167
+ return {
15168
+ kind: "evm.typed-data",
15169
+ signature: signEvmTypedData(request.typedData, priv)
15170
+ };
15171
+ } finally {
15172
+ child.wipePrivateData();
15173
+ }
15174
+ } finally {
15175
+ master.wipePrivateData();
15176
+ }
15177
+ };
15178
+
15179
+ // ../wallet-chains/dist/solana-sign.mjs
15180
+ var signSolanaMessage = (message, privateKey) => {
15181
+ if (privateKey.length !== 32)
15182
+ throw new ChainError("invalid-request", "private key must be a 32-byte seed");
15183
+ if (message.length === 0)
15184
+ throw new ChainError("invalid-request", "message must not be empty");
15185
+ const signature = ed25519.sign(message, privateKey);
15186
+ if (signature.length !== 64)
15187
+ throw new ChainError("invalid-request", "ed25519 produced a malformed signature");
15188
+ return signature;
15189
+ };
15190
+
15191
+ // ../wallet-kernel/src/modules/chains/solana.ts
15192
+ var executeSolana = (request, account, seed, intentOnly) => {
15193
+ const root = HDKey2.fromMasterSeed(seed);
15194
+ const child = root.derive(`m/44'/501'/${account.groupIndex}'/0'`);
15195
+ try {
15196
+ const priv = child.privateKey;
15197
+ const signer = solanaAddressFromPublicKey(ed25519.getPublicKey(priv));
15198
+ let normalized;
15199
+ try {
15200
+ normalized = normalizeSolana(request, signer);
15201
+ } catch (error) {
15202
+ mapChainError(error);
15203
+ }
15204
+ if (!deepEqual(normalized, request)) {
15205
+ throw new KernelError("invalid-input", "request is not normalized");
15206
+ }
15207
+ let intent = MESSAGE_INTENT;
15208
+ if (request.kind === "solana.transaction") {
15209
+ try {
15210
+ intent = decodeSolana(request, signer);
15211
+ } catch (error) {
15212
+ mapChainError(error);
15213
+ }
15214
+ }
15215
+ if (intentOnly) {
15216
+ return { prompt: intent };
15217
+ }
15218
+ return {
15219
+ kind: request.kind,
15220
+ signature: signSolanaMessage(request.message, priv)
15221
+ };
15222
+ } finally {
15223
+ wipe(child.privateKey);
15224
+ wipe(root.privateKey);
15225
+ }
15226
+ };
15227
+
15228
+ // ../wallet-kernel/src/modules/chains/index.ts
14965
15229
  var checkNetwork = (template, network) => {
14966
15230
  if (template.startsWith("evm.") && !network.startsWith("eip155:")) {
14967
15231
  throw new KernelError("invalid-input", "evm.bip44 requires an eip155 network");
@@ -15018,30 +15282,60 @@ var accountFor = (master, seed, template, network, groupIndex) => {
15018
15282
  account.wipePrivateData();
15019
15283
  }
15020
15284
  };
15021
- var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array);
15022
- var deepEqual = (a, b) => {
15023
- if (a === b) {
15024
- return true;
15285
+ var walletAccounts = async (ctx, params, session) => {
15286
+ const { dek } = ctx.session.require(session);
15287
+ const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === params.walletId);
15288
+ if (record === undefined) {
15289
+ throw new KernelError("not-found", "no such wallet");
15025
15290
  }
15026
- if (a instanceof Uint8Array || b instanceof Uint8Array) {
15027
- return a instanceof Uint8Array && b instanceof Uint8Array && a.length === b.length && a.every((byte, i) => byte === b[i]);
15291
+ checkNetwork(params.template, params.network);
15292
+ return withWalletSeed(ctx.platform.pbkdf2, dek, record, (seed) => {
15293
+ const master = HDKey.fromMasterSeed(seed, params.template.startsWith("btc.") ? bitcoinNetwork(params.network).bip32 : undefined);
15294
+ try {
15295
+ return accountFor(master, seed, params.template, params.network, params.groupIndex);
15296
+ } finally {
15297
+ master.wipePrivateData();
15298
+ }
15299
+ });
15300
+ };
15301
+ var chainSign = async (ctx, params, session) => {
15302
+ const { dek } = ctx.session.require(session);
15303
+ const { request, verify } = params;
15304
+ const { account } = request;
15305
+ if (account.kind !== "hd") {
15306
+ throw new KernelError("unsupported", "imported accounts are not yet supported");
15028
15307
  }
15029
- if (Array.isArray(a) || Array.isArray(b)) {
15030
- return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
15308
+ const [family] = request.kind.split(".", 1);
15309
+ const expected = family === "evm" ? ["evm.bip44"] : family === "solana" ? ["solana.bip44-change"] : ["btc.bip44", "btc.bip49", "btc.bip84", "btc.bip86"];
15310
+ if (!expected.includes(account.template)) {
15311
+ throw new KernelError("invalid-input", "account template does not match the request family");
15031
15312
  }
15032
- if (!isObj(a) || !isObj(b)) {
15033
- return false;
15313
+ const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === account.walletId);
15314
+ if (record === undefined) {
15315
+ throw new KernelError("not-found", "no such wallet");
15034
15316
  }
15035
- const ka = Object.keys(a);
15036
- const kb = new Set(Object.keys(b));
15037
- return ka.length === kb.size && ka.every((k) => kb.has(k) && deepEqual(a[k], b[k]));
15317
+ const execute = (seed, intentOnly) => {
15318
+ if (request.kind === "evm.transaction" || request.kind === "evm.personal-message" || request.kind === "evm.typed-data") {
15319
+ return executeEvm(request, account, seed, intentOnly);
15320
+ }
15321
+ if (request.kind === "bitcoin.psbt" || request.kind === "bitcoin.message") {
15322
+ return executeBitcoin(ctx.platform.random, request, account, seed, intentOnly);
15323
+ }
15324
+ return executeSolana(request, account, seed, intentOnly);
15325
+ };
15326
+ const withSeed = async (run) => withWalletSeed(ctx.platform.pbkdf2, dek, record, run);
15327
+ const prepared = await withSeed((seed) => execute(seed, true));
15328
+ if (!("prompt" in prepared)) {
15329
+ throw new KernelError("integrity", "unreachable: prepare pass signed");
15330
+ }
15331
+ await verifyFactor(ctx.platform, ctx.image, verify, dek, () => chainPrompt(promptLocale(ctx.platform.keystore?.locale ?? "en"), prepared.prompt));
15332
+ ctx.session.require(session);
15333
+ const signed = await withSeed((seed) => execute(seed, false));
15334
+ if ("prompt" in signed) {
15335
+ throw new KernelError("integrity", "unreachable: sign pass did not sign");
15336
+ }
15337
+ return signed;
15038
15338
  };
15039
- function mapChainError(error) {
15040
- if (error instanceof ChainError) {
15041
- throw new KernelError("invalid-input", "invalid sign request");
15042
- }
15043
- throw error;
15044
- }
15045
15339
  function createChainsModule() {
15046
15340
  const vault = {
15047
15341
  ownsRecord: () => false,
@@ -15052,348 +15346,22 @@ function createChainsModule() {
15052
15346
  lock: () => {
15053
15347
  return;
15054
15348
  },
15055
- backupSecrets: () => [],
15056
- backupRecords: () => [],
15057
15349
  walletDeleteOps: () => []
15058
15350
  };
15059
15351
  const handlers = {
15060
- "wallet.accounts": async (ctx, params, session) => {
15061
- const { dek } = ctx.session.require(session);
15062
- const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === params.walletId);
15063
- if (record === undefined) {
15064
- throw new KernelError("not-found", "no such wallet");
15065
- }
15066
- checkNetwork(params.template, params.network);
15067
- const entropy = openRecord(dek, record);
15068
- let seed;
15069
- try {
15070
- seed = await seedFromEntropy(entropy, ctx.platform.pbkdf2);
15071
- } finally {
15072
- wipe(entropy);
15073
- }
15074
- try {
15075
- const master = HDKey.fromMasterSeed(seed, params.template.startsWith("btc.") ? bitcoinNetwork(params.network).bip32 : undefined);
15076
- try {
15077
- return accountFor(master, seed, params.template, params.network, params.groupIndex);
15078
- } finally {
15079
- master.wipePrivateData();
15080
- }
15081
- } finally {
15082
- wipe(seed);
15083
- }
15084
- },
15085
- "chain.sign": async (ctx, params, session) => {
15086
- const { dek } = ctx.session.require(session);
15087
- const { request, verify } = params;
15088
- const { account } = request;
15089
- if (account.kind !== "hd") {
15090
- throw new KernelError("unsupported", "imported accounts are not yet supported");
15091
- }
15092
- const [family] = request.kind.split(".", 1);
15093
- const expected = family === "evm" ? ["evm.bip44"] : family === "solana" ? ["solana.bip44-change"] : ["btc.bip44", "btc.bip49", "btc.bip84", "btc.bip86"];
15094
- if (!expected.includes(account.template)) {
15095
- throw new KernelError("invalid-input", "account template does not match the request family");
15096
- }
15097
- const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === account.walletId);
15098
- if (record === undefined) {
15099
- throw new KernelError("not-found", "no such wallet");
15100
- }
15101
- const execute = (seed, intentOnly) => {
15102
- if (request.kind === "evm.transaction" || request.kind === "evm.personal-message" || request.kind === "evm.typed-data") {
15103
- const master = HDKey.fromMasterSeed(seed);
15104
- try {
15105
- const child = master.derive(`m/44'/60'/0'/0/${account.groupIndex}`);
15106
- try {
15107
- const priv = child.privateKey;
15108
- if (priv === null) {
15109
- throw new KernelError("integrity", "no private key at account path");
15110
- }
15111
- let normalized;
15112
- try {
15113
- normalized = normalizeEvm(request);
15114
- } catch (error) {
15115
- mapChainError(error);
15116
- }
15117
- if (!deepEqual(normalized, request)) {
15118
- throw new KernelError("invalid-input", "request is not normalized");
15119
- }
15120
- let intent;
15121
- try {
15122
- intent = decodeEvm(request);
15123
- } catch (error) {
15124
- mapChainError(error);
15125
- }
15126
- if (intentOnly) {
15127
- return { prompt: intent };
15128
- }
15129
- if (request.kind === "evm.transaction") {
15130
- return {
15131
- kind: "evm.transaction",
15132
- signedTransaction: signEvmTransaction(request.tx, priv)
15133
- };
15134
- }
15135
- if (request.kind === "evm.personal-message") {
15136
- return {
15137
- kind: "evm.personal-message",
15138
- signature: signEvmPersonalMessage(request.message, priv)
15139
- };
15140
- }
15141
- return {
15142
- kind: "evm.typed-data",
15143
- signature: signEvmTypedData(request.typedData, priv)
15144
- };
15145
- } finally {
15146
- child.wipePrivateData();
15147
- }
15148
- } finally {
15149
- master.wipePrivateData();
15150
- }
15151
- }
15152
- if (request.kind === "bitcoin.psbt" || request.kind === "bitcoin.message") {
15153
- const net = bitcoinNetwork(request.network);
15154
- const master = HDKey.fromMasterSeed(seed, net.bip32);
15155
- try {
15156
- const purpose = BTC_PURPOSE[account.template] ?? 84;
15157
- const { coinType } = net;
15158
- const hardened = 2147483648;
15159
- const accountNode = master.derive(`m/${purpose}'/${coinType}'/${account.groupIndex}'`);
15160
- const children = [];
15161
- const derivation = (owner) => {
15162
- if (purpose === 86) {
15163
- const claimed = (der) => der.fingerprint === master.fingerprint && isPath(der.path);
15164
- for (const [key, value] of owner.tapBip32Derivation ?? []) {
15165
- if (claimed(value.der)) {
15166
- return {
15167
- pubkey: key,
15168
- fingerprint: value.der.fingerprint,
15169
- path: value.der.path
15170
- };
15171
- }
15172
- }
15173
- return;
15174
- }
15175
- for (const [key, value] of owner.bip32Derivation ?? []) {
15176
- if (value.fingerprint === master.fingerprint) {
15177
- return { pubkey: key, fingerprint: value.fingerprint, path: value.path };
15178
- }
15179
- }
15180
- return;
15181
- };
15182
- const childAt = (path) => {
15183
- const [purposePath, coinPath, groupPath, change, index] = path;
15184
- if (path.length !== 5 || purposePath !== purpose + hardened || coinPath !== coinType + hardened || groupPath !== account.groupIndex + hardened || change === undefined || index === undefined || change !== 0 && change !== 1 || index < 0 || index >= hardened) {
15185
- throw new KernelError("invalid-input", "derivation path is not this account's");
15186
- }
15187
- const child = accountNode.deriveChild(change).deriveChild(index);
15188
- children.push(child);
15189
- return child;
15190
- };
15191
- const expectedPub = (pub) => purpose === 86 ? pub.slice(1) : pub;
15192
- const expectedScript = (pub) => purpose === 86 ? p2tr(pub.slice(1)).script : purpose === 49 ? p2sh(p2wpkh(pub)).script : purpose === 44 ? p2pkh(pub).script : p2wpkh(pub).script;
15193
- try {
15194
- if (request.kind === "bitcoin.psbt") {
15195
- const tx = Transaction.fromPSBT(request.psbt);
15196
- const inputs = [];
15197
- for (const idx of request.sign) {
15198
- const input = tx.getInput(idx);
15199
- const entry = derivation(input);
15200
- if (entry === undefined) {
15201
- throw new KernelError("invalid-input", `input ${idx}: derivation entry is not this account's`);
15202
- }
15203
- const child = childAt(entry.path);
15204
- const pub = child.publicKey;
15205
- const priv = child.privateKey;
15206
- if (pub === null || priv === null) {
15207
- throw new KernelError("integrity", "no key at derivation path");
15208
- }
15209
- if (!deepEqual(entry.pubkey, expectedPub(pub))) {
15210
- throw new KernelError("invalid-input", `input ${idx}: derivation pubkey is not ours`);
15211
- }
15212
- if (purpose === 44) {
15213
- if (input.nonWitnessUtxo === undefined) {
15214
- throw new KernelError("invalid-input", `input ${idx}: P2PKH spend requires nonWitnessUtxo`);
15215
- }
15216
- const vout = input.index;
15217
- const outs = input.nonWitnessUtxo.outputs;
15218
- const prevScript = vout === undefined ? undefined : outs[vout]?.script;
15219
- if (prevScript === undefined || !deepEqual(prevScript, expectedScript(pub))) {
15220
- throw new KernelError("invalid-input", `input ${idx}: nonWitnessUtxo prevout is not this key's`);
15221
- }
15222
- } else {
15223
- const prevout = input.witnessUtxo;
15224
- if (prevout === undefined || !deepEqual(prevout.script, expectedScript(pub))) {
15225
- throw new KernelError("invalid-input", `input ${idx}: prevout script is not this key's`);
15226
- }
15227
- if (purpose === 49 && (input.redeemScript === undefined || !deepEqual(input.redeemScript, p2wpkh(pub).script))) {
15228
- throw new KernelError("invalid-input", `input ${idx}: redeemScript is not this key's`);
15229
- }
15230
- }
15231
- inputs.push({ index: idx, privateKey: priv });
15232
- }
15233
- const ownScripts = new Set;
15234
- for (let i = 0;i < tx.outputsLength; i++) {
15235
- const output = tx.getOutput(i);
15236
- if (output.script === undefined) {
15237
- continue;
15238
- }
15239
- const entry = derivation(output);
15240
- if (entry === undefined) {
15241
- continue;
15242
- }
15243
- try {
15244
- const child = childAt(entry.path);
15245
- const pub = child.publicKey;
15246
- if (pub !== null && deepEqual(output.script, expectedScript(pub))) {
15247
- ownScripts.add(hex2(output.script));
15248
- }
15249
- } catch {
15250
- continue;
15251
- }
15252
- }
15253
- let normalized;
15254
- try {
15255
- normalized = normalizeBitcoin(request);
15256
- } catch (error) {
15257
- mapChainError(error);
15258
- }
15259
- if (!deepEqual(normalized, request)) {
15260
- throw new KernelError("invalid-input", "request is not normalized");
15261
- }
15262
- let intent;
15263
- try {
15264
- intent = decodeBitcoinPsbt(request, ownScripts);
15265
- } catch (error) {
15266
- mapChainError(error);
15267
- }
15268
- if (intentOnly) {
15269
- return { prompt: intent };
15270
- }
15271
- return {
15272
- kind: "bitcoin.psbt",
15273
- signedPsbt: signBitcoinPsbt(request.psbt, inputs, () => ctx.platform.random(32))
15274
- };
15275
- }
15276
- if (request.format === "legacy" && account.template !== "btc.bip44") {
15277
- throw new KernelError("unsupported", "legacy message format is btc.bip44-only");
15278
- }
15279
- const child = childAt([
15280
- purpose + hardened,
15281
- coinType + hardened,
15282
- account.groupIndex + hardened,
15283
- request.change,
15284
- request.index
15285
- ]);
15286
- const pub = child.publicKey;
15287
- const priv = child.privateKey;
15288
- if (pub === null || priv === null) {
15289
- throw new KernelError("integrity", "no key at derivation path");
15290
- }
15291
- const derived = purpose === 86 ? p2tr(pub.slice(1), undefined, net.params).address : purpose === 49 ? p2sh(p2wpkh(pub, net.params), net.params).address : purpose === 44 ? p2pkh(pub, net.params).address : p2wpkh(pub, net.params).address;
15292
- if (derived !== request.address) {
15293
- throw new KernelError("invalid-input", "address is not ours");
15294
- }
15295
- let normalized;
15296
- try {
15297
- normalized = normalizeBitcoin(request);
15298
- } catch (error) {
15299
- mapChainError(error);
15300
- }
15301
- if (!deepEqual(normalized, request)) {
15302
- throw new KernelError("invalid-input", "request is not normalized");
15303
- }
15304
- try {
15305
- decodeMessageTarget(request);
15306
- } catch (error) {
15307
- mapChainError(error);
15308
- }
15309
- if (intentOnly) {
15310
- return { prompt: MESSAGE_INTENT };
15311
- }
15312
- return {
15313
- kind: "bitcoin.message",
15314
- signature: signBitcoinMessage(request, priv, () => ctx.platform.random(32))
15315
- };
15316
- } finally {
15317
- for (const child of children) {
15318
- child.wipePrivateData();
15319
- }
15320
- accountNode.wipePrivateData();
15321
- }
15322
- } finally {
15323
- master.wipePrivateData();
15324
- }
15325
- }
15326
- const root = HDKey2.fromMasterSeed(seed);
15327
- const child = root.derive(`m/44'/501'/${account.groupIndex}'/0'`);
15328
- try {
15329
- const priv = child.privateKey;
15330
- const signer = solanaAddressFromPublicKey(ed25519.getPublicKey(priv));
15331
- let normalized;
15332
- try {
15333
- normalized = normalizeSolana(request, signer);
15334
- } catch (error) {
15335
- mapChainError(error);
15336
- }
15337
- if (!deepEqual(normalized, request)) {
15338
- throw new KernelError("invalid-input", "request is not normalized");
15339
- }
15340
- let intent = MESSAGE_INTENT;
15341
- if (request.kind === "solana.transaction") {
15342
- try {
15343
- intent = decodeSolana(request, signer);
15344
- } catch (error) {
15345
- mapChainError(error);
15346
- }
15347
- }
15348
- if (intentOnly) {
15349
- return { prompt: intent };
15350
- }
15351
- return {
15352
- kind: request.kind,
15353
- signature: signSolanaMessage(request.message, priv)
15354
- };
15355
- } finally {
15356
- wipe(child.privateKey);
15357
- wipe(root.privateKey);
15358
- }
15359
- };
15360
- const withSeed = async (run) => {
15361
- const entropy = openRecord(dek, record);
15362
- let seed;
15363
- try {
15364
- seed = await seedFromEntropy(entropy, ctx.platform.pbkdf2);
15365
- } finally {
15366
- wipe(entropy);
15367
- }
15368
- try {
15369
- return run(seed);
15370
- } finally {
15371
- wipe(seed);
15372
- }
15373
- };
15374
- const prepared = await withSeed((seed) => execute(seed, true));
15375
- if (!("prompt" in prepared)) {
15376
- throw new KernelError("integrity", "unreachable: prepare pass signed");
15377
- }
15378
- await verifyFactor(ctx.platform, ctx.image, verify, dek, () => chainPrompt(promptLocale(ctx.platform.keystore?.locale ?? "en"), prepared.prompt));
15379
- ctx.session.require(session);
15380
- const signed = await withSeed((seed) => execute(seed, false));
15381
- if ("prompt" in signed) {
15382
- throw new KernelError("integrity", "unreachable: sign pass did not sign");
15383
- }
15384
- return signed;
15385
- }
15352
+ "wallet.accounts": walletAccounts,
15353
+ "chain.sign": chainSign
15386
15354
  };
15387
15355
  return { vault, handlers };
15388
15356
  }
15389
15357
 
15390
15358
  // ../wallet-kernel/src/modules/nostr/derive.ts
15391
15359
  var NIP06_PATH = "m/44'/1237'/i'/0/0";
15392
- function nostrKeyAt(master, groupIndex) {
15393
- if (!Number.isSafeInteger(groupIndex) || groupIndex < 0 || groupIndex > 2147483647) {
15394
- throw new KernelError("invalid-input", "group index out of range");
15360
+ function nostrKeyAt(master, index) {
15361
+ if (!Number.isSafeInteger(index) || index < 0 || index > 2147483647) {
15362
+ throw new KernelError("invalid-input", "identity index out of range");
15395
15363
  }
15396
- const path = NIP06_PATH.split("/").map((segment) => segment === "i'" ? `${groupIndex}'` : segment).join("/");
15364
+ const path = NIP06_PATH.split("/").map((segment) => segment === "i'" ? `${index}'` : segment).join("/");
15397
15365
  const node = master.derive(path);
15398
15366
  try {
15399
15367
  const key = node.privateKey;
@@ -15408,32 +15376,6 @@ function nostrKeyAt(master, groupIndex) {
15408
15376
 
15409
15377
  // ../../node_modules/.bun/@qntx+nostr@0.15.3+ea9f70ecde856c26/node_modules/@qntx/nostr/dist/nips/nip19.mjs
15410
15378
  var Bech32MaxSize2 = 5000;
15411
- var Nip19Error2 = class extends NostrError {
15412
- name = "Nip19Error";
15413
- };
15414
- function parseTLV(data) {
15415
- const result = {};
15416
- let rest = data;
15417
- while (rest.length > 0) {
15418
- if (rest.length < 2)
15419
- throw new Nip19Error2("not enough data to read TLV");
15420
- const t = rest.at(0);
15421
- const l = rest.at(1);
15422
- if (t === undefined || l === undefined)
15423
- throw new Nip19Error2("not enough data to read TLV");
15424
- const v = rest.slice(2, 2 + l);
15425
- rest = rest.slice(2 + l);
15426
- if (v.length < l)
15427
- throw new Nip19Error2(`not enough data to read on TLV ${t}`);
15428
- result[t] = result[t] ?? [];
15429
- result[t].push(v);
15430
- }
15431
- return result;
15432
- }
15433
- function assertNip19Kind(kind) {
15434
- if (!Number.isInteger(kind) || kind < 0 || kind > 65535)
15435
- throw new Nip19Error2(`invalid kind: ${kind}`);
15436
- }
15437
15379
  function encodeBech32(prefix, data) {
15438
15380
  const words = bech32.toWords(data);
15439
15381
  return bech32.encode(prefix, words, Bech32MaxSize2);
@@ -15445,106 +15387,6 @@ function nsecEncode2(key) {
15445
15387
  assertByteLength(key, 32, "secret key");
15446
15388
  return encodeBytes("nsec", key);
15447
15389
  }
15448
- function readUint32(bytes) {
15449
- return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0);
15450
- }
15451
- function decode3(code) {
15452
- let prefix;
15453
- let data;
15454
- try {
15455
- const { prefix: hrp, words } = bech32.decode(code, Bech32MaxSize2);
15456
- prefix = hrp;
15457
- data = new Uint8Array(bech32.fromWords(words));
15458
- } catch (error) {
15459
- throw new Nip19Error2(`invalid bech32: ${errorMessage(error)}`, { cause: error });
15460
- }
15461
- switch (prefix) {
15462
- case "nprofile": {
15463
- const tlv = parseTLV(data);
15464
- if (!tlv[0]?.[0])
15465
- throw new Nip19Error2("missing TLV 0 for nprofile");
15466
- if (tlv[0][0].length !== 32)
15467
- throw new Nip19Error2("TLV 0 should be 32 bytes");
15468
- return {
15469
- type: "nprofile",
15470
- data: {
15471
- pubkey: bytesToHex$1(tlv[0][0]),
15472
- relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
15473
- }
15474
- };
15475
- }
15476
- case "nevent": {
15477
- const tlv = parseTLV(data);
15478
- if (!tlv[0]?.[0])
15479
- throw new Nip19Error2("missing TLV 0 for nevent");
15480
- if (tlv[0][0].length !== 32)
15481
- throw new Nip19Error2("TLV 0 should be 32 bytes");
15482
- if (tlv[2]?.[0] && tlv[2][0].length !== 32)
15483
- throw new Nip19Error2("TLV 2 should be 32 bytes");
15484
- if (tlv[3]?.[0] && tlv[3][0].length !== 4)
15485
- throw new Nip19Error2("TLV 3 should be 4 bytes");
15486
- const pointer = {
15487
- id: bytesToHex$1(tlv[0][0]),
15488
- relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
15489
- };
15490
- const author = tlv[2]?.[0];
15491
- if (author !== undefined)
15492
- pointer.author = bytesToHex$1(author);
15493
- const kind = tlv[3]?.[0];
15494
- if (kind !== undefined) {
15495
- pointer.kind = readUint32(kind);
15496
- assertNip19Kind(pointer.kind);
15497
- }
15498
- return {
15499
- type: "nevent",
15500
- data: pointer
15501
- };
15502
- }
15503
- case "naddr": {
15504
- const tlv = parseTLV(data);
15505
- if (!tlv[0]?.[0])
15506
- throw new Nip19Error2("missing TLV 0 for naddr");
15507
- if (!tlv[2]?.[0])
15508
- throw new Nip19Error2("missing TLV 2 for naddr");
15509
- if (tlv[2][0].length !== 32)
15510
- throw new Nip19Error2("TLV 2 should be 32 bytes");
15511
- if (!tlv[3]?.[0])
15512
- throw new Nip19Error2("missing TLV 3 for naddr");
15513
- if (tlv[3][0].length !== 4)
15514
- throw new Nip19Error2("TLV 3 should be 4 bytes");
15515
- const naddrKind = readUint32(tlv[3][0]);
15516
- assertNip19Kind(naddrKind);
15517
- return {
15518
- type: "naddr",
15519
- data: {
15520
- identifier: utf8Decoder.decode(tlv[0][0]),
15521
- pubkey: bytesToHex$1(tlv[2][0]),
15522
- kind: naddrKind,
15523
- relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
15524
- }
15525
- };
15526
- }
15527
- case "nsec":
15528
- if (data.length !== 32)
15529
- throw new Nip19Error2("nsec must be 32 bytes");
15530
- if (!secp256k1.utils.isValidSecretKey(data))
15531
- throw new Nip19Error2("invalid nsec secret key");
15532
- return {
15533
- type: "nsec",
15534
- data
15535
- };
15536
- case "npub":
15537
- case "note":
15538
- if (data.length !== 32)
15539
- throw new Nip19Error2(`${prefix} must be 32 bytes`);
15540
- return {
15541
- type: prefix,
15542
- data: bytesToHex$1(data)
15543
- };
15544
- default:
15545
- throw new Nip19Error2(`unknown prefix ${prefix}`);
15546
- }
15547
- }
15548
15390
 
15549
15391
  // ../../node_modules/.bun/@noble+hashes@2.4.0/node_modules/@noble/hashes/scrypt.js
15550
15392
  function XorAndSalsa(prev, pi, input, ii, out, oi) {
@@ -15709,7 +15551,6 @@ async function scryptAsync(password, salt, opts) {
15709
15551
  var VERSION2 = 2;
15710
15552
  var SALT_LEN = 16;
15711
15553
  var NONCE_LEN = 24;
15712
- var PAYLOAD_LEN = 91;
15713
15554
  var LOGN_MIN = 1;
15714
15555
  var LOGN_MAX = 22;
15715
15556
  var SCRYPT_R = 8;
@@ -15753,60 +15594,6 @@ async function encrypt4(secretKey, password, opts) {
15753
15594
  const bytes = concatBytes(Uint8Array.from([VERSION2]), Uint8Array.from([logn]), salt, nonce, aad, ciphertext);
15754
15595
  return encodeBytes("ncryptsec", bytes);
15755
15596
  }
15756
- async function decrypt4(ncryptsec, password, opts) {
15757
- const { maxLogN } = opts;
15758
- if (!Number.isInteger(maxLogN) || maxLogN < LOGN_MIN || maxLogN > LOGN_MAX)
15759
- throw new Nip49Error(`invalid maxLogN ${maxLogN}, expected integer ${LOGN_MIN}..${LOGN_MAX}`);
15760
- let prefix;
15761
- let b;
15762
- try {
15763
- const decoded = bech32.decode(ncryptsec, Bech32MaxSize2);
15764
- ({ prefix } = decoded);
15765
- b = new Uint8Array(bech32.fromWords(decoded.words));
15766
- } catch (error) {
15767
- throw new Nip49Error("invalid ncryptsec", { cause: error });
15768
- }
15769
- if (prefix !== "ncryptsec")
15770
- throw new Nip49Error(`invalid prefix ${prefix}, expected 'ncryptsec'`);
15771
- if (b.length !== PAYLOAD_LEN)
15772
- throw new Nip49Error("invalid ncryptsec length");
15773
- const version = b.at(0);
15774
- if (version === undefined)
15775
- throw new Nip49Error("invalid ncryptsec length");
15776
- if (version !== VERSION2)
15777
- throw new Nip49Error(`invalid version ${version}, expected 0x02`);
15778
- const logn = b.at(1);
15779
- if (logn === undefined)
15780
- throw new Nip49Error("invalid ncryptsec length");
15781
- if (logn > maxLogN)
15782
- throw new Nip49Error(`logn ${logn} exceeds maxLogN ${maxLogN}`);
15783
- const salt = b.subarray(2, 18);
15784
- const nonce = b.subarray(18, 42);
15785
- const ksb = b.at(42);
15786
- if (ksb === undefined)
15787
- throw new Nip49Error("invalid ncryptsec length");
15788
- if (ksb !== 0 && ksb !== 1 && ksb !== 2)
15789
- throw new Nip49Error(`invalid key security byte ${ksb}, expected 0x00, 0x01, or 0x02`);
15790
- const aad = Uint8Array.from([ksb]);
15791
- const ciphertext = b.subarray(43);
15792
- try {
15793
- const key = await deriveKey(password, salt, logn, opts.scrypt ?? nobleScrypt);
15794
- try {
15795
- const secret = xchacha20poly1305(key, nonce, aad).decrypt(ciphertext);
15796
- if (!secp256k1.utils.isValidSecretKey(secret)) {
15797
- secret.fill(0);
15798
- throw new Nip49Error("invalid secret key");
15799
- }
15800
- return secret;
15801
- } finally {
15802
- key.fill(0);
15803
- }
15804
- } catch (error) {
15805
- if (error instanceof Nip49Error)
15806
- throw error;
15807
- throw new Nip49Error("failed to decrypt", { cause: error });
15808
- }
15809
- }
15810
15597
 
15811
15598
  // ../wallet-kernel/src/modules/nostr/pool.ts
15812
15599
  class SignerPool {
@@ -15849,63 +15636,6 @@ class SignerPool {
15849
15636
  this.signers.clear();
15850
15637
  }
15851
15638
  }
15852
- function generateSecretKey(random, backend) {
15853
- for (;; ) {
15854
- const candidate = random(32);
15855
- try {
15856
- Keys.fromSecretKey(candidate, backend);
15857
- return candidate;
15858
- } catch {
15859
- wipe(candidate);
15860
- }
15861
- }
15862
- }
15863
- function secretKeyFromNsec(nsec) {
15864
- const text = decodeUtf8Secret(nsec);
15865
- try {
15866
- const decoded = decode3(text);
15867
- if (decoded.type !== "nsec") {
15868
- throw new KernelError("invalid-input", "expected an nsec bech32 string");
15869
- }
15870
- return new Uint8Array(decoded.data);
15871
- } catch (error) {
15872
- if (error instanceof KernelError) {
15873
- throw error;
15874
- }
15875
- throw new KernelError("invalid-input", "invalid nsec");
15876
- }
15877
- }
15878
- async function secretKeyFromNcryptsec(ncryptsec, password, maxLogN, scrypt) {
15879
- const text = decodeUtf8Secret(password);
15880
- let payload;
15881
- try {
15882
- const decoded = bech32.decode(ncryptsec, Bech32MaxSize2);
15883
- payload = new Uint8Array(bech32.fromWords(decoded.words));
15884
- if (decoded.prefix !== "ncryptsec" || payload.length !== 91 || payload.at(0) !== 2) {
15885
- throw new KernelError("invalid-input", "malformed ncryptsec");
15886
- }
15887
- } catch (error) {
15888
- if (error instanceof KernelError) {
15889
- throw error;
15890
- }
15891
- throw new KernelError("invalid-input", "malformed ncryptsec");
15892
- }
15893
- const logN = payload.at(1) ?? 0;
15894
- if (logN > maxLogN) {
15895
- throw new KernelError("unsupported", "ncryptsec scrypt logN exceeds the policy limit");
15896
- }
15897
- try {
15898
- return await decrypt4(ncryptsec, text, {
15899
- maxLogN,
15900
- ...scrypt === undefined ? {} : { scrypt }
15901
- });
15902
- } catch (error) {
15903
- if (error instanceof Nip49Error && error.cause instanceof RangeError) {
15904
- throw new KernelError("unavailable", "ncryptsec scrypt allocation failed");
15905
- }
15906
- throw new KernelError("wrong-password", "invalid ncryptsec or wrong password");
15907
- }
15908
- }
15909
15639
  function nsecFromSecretKey(secretKey) {
15910
15640
  return new TextEncoder().encode(nsecEncode2(secretKey));
15911
15641
  }
@@ -15945,58 +15675,27 @@ async function unwrapGiftWrap(pool, publicKey, event, backend) {
15945
15675
  // ../wallet-kernel/src/modules/nostr/record.ts
15946
15676
  var NOSTR_KEY_KIND = "nostr-key";
15947
15677
  function encodeNostrKeyHeader(header) {
15948
- if (header.origin === "derived") {
15949
- return JSON.stringify({
15950
- publicKey: header.publicKey,
15951
- origin: header.origin,
15952
- walletId: header.walletId,
15953
- groupIndex: header.groupIndex,
15954
- createdAt: header.createdAt
15955
- });
15956
- }
15957
- return header.origin === "nip46-client" ? JSON.stringify({
15958
- publicKey: header.publicKey,
15959
- origin: header.origin,
15960
- createdAt: header.createdAt
15961
- }) : JSON.stringify({
15678
+ return JSON.stringify({
15962
15679
  publicKey: header.publicKey,
15963
- origin: header.origin,
15964
- backedUp: header.backedUp,
15680
+ walletId: header.walletId,
15681
+ index: header.index,
15965
15682
  createdAt: header.createdAt
15966
15683
  });
15967
15684
  }
15968
15685
  function parseNostrKeyHeader(text) {
15969
15686
  const object = headerObject(text);
15970
- const publicKey = asPublicKey(object["publicKey"]);
15971
- const createdAt = asCreatedAt(object["createdAt"]);
15972
- if (object["origin"] === "derived") {
15973
- expectKeys(object, ["publicKey", "origin", "walletId", "groupIndex", "createdAt"]);
15974
- return {
15975
- publicKey,
15976
- origin: "derived",
15977
- walletId: asWalletId(object["walletId"]),
15978
- groupIndex: asGroupIndex(object["groupIndex"]),
15979
- createdAt
15980
- };
15981
- }
15982
- if (object["origin"] === "nip46-client") {
15983
- expectKeys(object, ["publicKey", "origin", "createdAt"]);
15984
- return { publicKey, origin: "nip46-client", createdAt };
15985
- }
15986
- expectKeys(object, ["publicKey", "origin", "backedUp", "createdAt"]);
15987
- const { origin } = object;
15988
- if (origin !== "nsec" && origin !== "ncryptsec" && origin !== "generated") {
15989
- throw headerFailure();
15990
- }
15991
- return { publicKey, origin, backedUp: asBoolean(object["backedUp"]), createdAt };
15687
+ expectKeys(object, ["publicKey", "walletId", "index", "createdAt"]);
15688
+ return {
15689
+ publicKey: asPublicKey(object["publicKey"]),
15690
+ walletId: asWalletId(object["walletId"]),
15691
+ index: asIdentityIndex(object["index"]),
15692
+ createdAt: asCreatedAt(object["createdAt"])
15693
+ };
15992
15694
  }
15993
15695
  function nostrKeyInfo2(header) {
15994
- const standalone = header.origin !== "derived" && header.origin !== "nip46-client";
15995
15696
  return {
15996
- ref: header.origin === "derived" ? { kind: "derived", walletId: header.walletId, groupIndex: header.groupIndex } : header.origin === "nip46-client" ? { kind: "nip46-client", id: header.publicKey } : { kind: "standalone", id: header.publicKey },
15697
+ ref: { kind: "derived", walletId: header.walletId, index: header.index },
15997
15698
  publicKey: header.publicKey,
15998
- origin: header.origin,
15999
- ...standalone ? { backedUp: header.backedUp } : {},
16000
15699
  createdAt: header.createdAt
16001
15700
  };
16002
15701
  }
@@ -16004,14 +15703,39 @@ function nostrStatus2(records) {
16004
15703
  const keys = [];
16005
15704
  let corrupted = false;
16006
15705
  for (const record of records) {
16007
- try {
16008
- keys.push(nostrKeyInfo2(parseNostrKeyHeader(record.header)));
16009
- } catch {
16010
- corrupted = true;
15706
+ if (record.kind === NOSTR_KEY_KIND) {
15707
+ try {
15708
+ keys.push(nostrKeyInfo2(parseNostrKeyHeader(record.header)));
15709
+ } catch {
15710
+ corrupted = true;
15711
+ }
15712
+ } else if (record.kind === NOSTR_SYNC_KEY_KIND) {
15713
+ try {
15714
+ parseSyncKeyHeader(record.header);
15715
+ } catch {
15716
+ corrupted = true;
15717
+ }
16011
15718
  }
16012
15719
  }
16013
15720
  return { keys, corrupted };
16014
15721
  }
15722
+ var NOSTR_SYNC_KEY_KIND = "nostr-sync-key";
15723
+ function encodeSyncKeyHeader(header) {
15724
+ return JSON.stringify({
15725
+ publicKey: header.publicKey,
15726
+ walletId: header.walletId,
15727
+ createdAt: header.createdAt
15728
+ });
15729
+ }
15730
+ function parseSyncKeyHeader(text) {
15731
+ const object = headerObject(text);
15732
+ expectKeys(object, ["publicKey", "walletId", "createdAt"]);
15733
+ return {
15734
+ publicKey: asPublicKey(object["publicKey"]),
15735
+ walletId: asWalletId(object["walletId"]),
15736
+ createdAt: asCreatedAt(object["createdAt"])
15737
+ };
15738
+ }
16015
15739
 
16016
15740
  // ../wallet-kernel/src/modules/nostr/keys.ts
16017
15741
  function keyRecord(ctx, dek, secretKey, header) {
@@ -16022,114 +15746,57 @@ function ensureNewKey(ctx, publicKey) {
16022
15746
  throw new KernelError("already-exists", "nostr key already exists");
16023
15747
  }
16024
15748
  }
16025
- async function addKey(ctx, secretKey, origin, backedUp, factor, requestSession) {
16026
- const gated = gate(ctx, factor, requestSession);
16027
- const publicKey = getPublicKey(secretKey);
16028
- ensureNewKey(ctx, publicKey);
16029
- const header = {
16030
- publicKey,
16031
- origin,
16032
- backedUp,
16033
- createdAt: ctx.platform.now()
16034
- };
16035
- const record = keyRecord(ctx, gated.dek, secretKey, header);
16036
- const session = await commitRecords(ctx, gated, factor, [record]);
16037
- return { key: nostrKeyInfo2(header), session };
16038
- }
16039
- async function importKey(ctx, params, requestSession) {
16040
- const { input } = params;
16041
- const secretKey = input.kind === "nsec" ? secretKeyFromNsec(input.nsec) : await secretKeyFromNcryptsec(input.ncryptsec, input.password, ctx.platform.policy.maxScryptLogN);
16042
- try {
16043
- return await addKey(ctx, secretKey, input.kind, true, params.factor, requestSession);
16044
- } finally {
16045
- wipe(secretKey);
16046
- }
16047
- }
16048
- async function generateKey(ctx, params, requestSession) {
16049
- const secretKey = generateSecretKey(ctx.platform.random, ctx.platform.backends.nostr);
16050
- try {
16051
- return await addKey(ctx, secretKey, "generated", false, params.factor, requestSession);
16052
- } finally {
16053
- wipe(secretKey);
16054
- }
16055
- }
16056
- async function createNip46ClientKey(ctx, requestSession) {
16057
- const { dek } = ctx.session.require(requestSession);
16058
- const secretKey = generateSecretKey(ctx.platform.random, ctx.platform.backends.nostr);
16059
- try {
16060
- const publicKey = getPublicKey(secretKey);
16061
- ensureNewKey(ctx, publicKey);
16062
- const header = {
16063
- publicKey,
16064
- origin: "nip46-client",
16065
- createdAt: ctx.platform.now()
16066
- };
16067
- await ctx.commit([{ op: "put-record", record: keyRecord(ctx, dek, secretKey, header) }]);
16068
- return nostrKeyInfo2(header);
16069
- } finally {
16070
- wipe(secretKey);
16071
- }
16072
- }
16073
15749
  async function deriveKey2(ctx, params, requestSession) {
16074
15750
  const { dek } = ctx.session.require(requestSession);
16075
15751
  const record = findRecord(ctx.image, "entropy", params.walletId);
16076
- const entropy = openRecord(dek, record);
16077
- const seed = await seedFromEntropy(entropy, ctx.platform.pbkdf2);
16078
- wipe(entropy);
16079
- const master = masterKey(seed);
16080
- wipe(seed);
16081
- try {
16082
- const secretKey = nostrKeyAt(master, params.groupIndex);
15752
+ return withWalletSeed(ctx.platform.pbkdf2, dek, record, async (seed) => {
15753
+ const master = masterKey(seed);
16083
15754
  try {
16084
- const publicKey = getPublicKey(secretKey);
16085
- ensureNewKey(ctx, publicKey);
16086
- const header = {
16087
- publicKey,
16088
- origin: "derived",
16089
- walletId: params.walletId,
16090
- groupIndex: params.groupIndex,
16091
- createdAt: ctx.platform.now()
16092
- };
16093
- await ctx.commit([{ op: "put-record", record: keyRecord(ctx, dek, secretKey, header) }]);
16094
- return nostrKeyInfo2(header);
15755
+ const secretKey = nostrKeyAt(master, params.index);
15756
+ try {
15757
+ const publicKey = getPublicKey(secretKey);
15758
+ ensureNewKey(ctx, publicKey);
15759
+ const header = {
15760
+ publicKey,
15761
+ walletId: params.walletId,
15762
+ index: params.index,
15763
+ createdAt: ctx.platform.now()
15764
+ };
15765
+ await ctx.commit([{ op: "put-record", record: keyRecord(ctx, dek, secretKey, header) }]);
15766
+ return nostrKeyInfo2(header);
15767
+ } finally {
15768
+ wipe(secretKey);
15769
+ }
16095
15770
  } finally {
16096
- wipe(secretKey);
15771
+ master.wipePrivateData();
16097
15772
  }
16098
- } finally {
16099
- master.wipePrivateData();
16100
- }
15773
+ });
16101
15774
  }
16102
15775
  async function discover(ctx, params, requestSession) {
16103
15776
  const { dek } = ctx.session.require(requestSession);
16104
15777
  const record = findRecord(ctx.image, "entropy", params.walletId);
16105
- const entropy = openRecord(dek, record);
15778
+ if (params.from + params.count - 1 > 2147483646) {
15779
+ throw new KernelError("invalid-input", "identity range exceeds 0x7ffffffe");
15780
+ }
16106
15781
  const keys = [];
16107
- const seed = await seedFromEntropy(entropy, ctx.platform.pbkdf2);
16108
- wipe(entropy);
16109
- const master = masterKey(seed);
16110
- wipe(seed);
16111
- try {
16112
- for (let i = 0;i < params.count; i++) {
16113
- const groupIndex = params.from + i;
16114
- const secretKey = nostrKeyAt(master, groupIndex);
16115
- keys.push({ groupIndex, publicKey: getPublicKey(secretKey) });
16116
- wipe(secretKey);
15782
+ return withWalletSeed(ctx.platform.pbkdf2, dek, record, (seed) => {
15783
+ const master = masterKey(seed);
15784
+ try {
15785
+ for (let i = 0;i < params.count; i++) {
15786
+ const index = params.from + i;
15787
+ const secretKey = nostrKeyAt(master, index);
15788
+ keys.push({ index, publicKey: getPublicKey(secretKey) });
15789
+ wipe(secretKey);
15790
+ }
15791
+ return { keys };
15792
+ } finally {
15793
+ master.wipePrivateData();
16117
15794
  }
16118
- return { keys };
16119
- } finally {
16120
- master.wipePrivateData();
16121
- }
15795
+ });
16122
15796
  }
16123
15797
  async function removeKey(ctx, params, requestSession) {
16124
- const { dek } = ctx.session.require(requestSession);
16125
- const record = findRecord(ctx.image, NOSTR_KEY_KIND, params.publicKey);
16126
- const header = parseNostrKeyHeader(record.header);
16127
- if (header.origin !== "nip46-client") {
16128
- if (params.verify === undefined) {
16129
- throw new KernelError("invalid-input", "factor verification is required");
16130
- }
16131
- await verifyFactor(ctx.platform, ctx.image, params.verify, dek, corePromptFor(ctx.platform.keystore, "remove-key"));
16132
- }
15798
+ ctx.session.require(requestSession);
15799
+ findRecord(ctx.image, NOSTR_KEY_KIND, params.publicKey);
16133
15800
  await ctx.commit([{ op: "delete-record", kind: NOSTR_KEY_KIND, id: params.publicKey }]);
16134
15801
  return null;
16135
15802
  }
@@ -16137,19 +15804,9 @@ async function exportKey(ctx, params, requestSession) {
16137
15804
  const { dek } = ctx.session.require(requestSession);
16138
15805
  await verifyFactor(ctx.platform, ctx.image, params.verify, dek, corePromptFor(ctx.platform.keystore, "export-key"));
16139
15806
  const record = findRecord(ctx.image, NOSTR_KEY_KIND, params.publicKey);
16140
- const header = parseNostrKeyHeader(record.header);
16141
15807
  const secretKey = openRecord(dek, record);
16142
15808
  try {
16143
15809
  const exported = params.format.kind === "nsec" ? nsecFromSecretKey(secretKey) : await ncryptsecFromSecretKey(secretKey, params.format.password);
16144
- if (header.origin !== "derived" && header.origin !== "nip46-client" && !header.backedUp) {
16145
- const updated = { ...header, backedUp: true };
16146
- await ctx.commit([
16147
- {
16148
- op: "put-record",
16149
- record: keyRecord(ctx, dek, secretKey, updated)
16150
- }
16151
- ]);
16152
- }
16153
15810
  return exported;
16154
15811
  } finally {
16155
15812
  wipe(secretKey);
@@ -16186,11 +15843,93 @@ async function unwrapGiftWraps(ctx, pool, params, requestSession) {
16186
15843
  return { results };
16187
15844
  }
16188
15845
 
15846
+ // ../wallet-kernel/src/modules/nostr/sync.ts
15847
+ var SYNC_INDEX = 2147483647;
15848
+ function syncRecord(ctx, walletId) {
15849
+ findRecord(ctx.image, "entropy", walletId);
15850
+ for (const record of ctx.image.records) {
15851
+ if (record.kind === NOSTR_SYNC_KEY_KIND) {
15852
+ const header = parseSyncKeyHeader(record.header);
15853
+ if (header.walletId === walletId) {
15854
+ return record;
15855
+ }
15856
+ }
15857
+ }
15858
+ throw new KernelError("not-found", "no sync key for this wallet");
15859
+ }
15860
+ async function syncKey(ctx, params, requestSession) {
15861
+ const { dek } = ctx.session.require(requestSession);
15862
+ try {
15863
+ return { publicKey: parseSyncKeyHeader(syncRecord(ctx, params.walletId).header).publicKey };
15864
+ } catch (error) {
15865
+ if (!(error instanceof KernelError && error.code === "not-found")) {
15866
+ throw error;
15867
+ }
15868
+ }
15869
+ const wallet = findRecord(ctx.image, "entropy", params.walletId);
15870
+ return withWalletSeed(ctx.platform.pbkdf2, dek, wallet, async (seed) => {
15871
+ const master = masterKey(seed);
15872
+ try {
15873
+ const secretKey = nostrKeyAt(master, SYNC_INDEX);
15874
+ try {
15875
+ const publicKey = getPublicKey(secretKey);
15876
+ const header = {
15877
+ publicKey,
15878
+ walletId: params.walletId,
15879
+ createdAt: ctx.platform.now()
15880
+ };
15881
+ const record = sealRecord(ctx.platform, dek, NOSTR_SYNC_KEY_KIND, publicKey, encodeSyncKeyHeader(header), new Uint8Array(secretKey));
15882
+ try {
15883
+ await ctx.commit([{ op: "put-record", record }]);
15884
+ } catch (error) {
15885
+ if (!(error instanceof KernelError && error.code === "conflict")) {
15886
+ throw error;
15887
+ }
15888
+ return {
15889
+ publicKey: parseSyncKeyHeader(syncRecord(ctx, params.walletId).header).publicKey
15890
+ };
15891
+ }
15892
+ return { publicKey };
15893
+ } finally {
15894
+ wipe(secretKey);
15895
+ }
15896
+ } finally {
15897
+ master.wipePrivateData();
15898
+ }
15899
+ });
15900
+ }
15901
+ function requireSyncSigner(ctx, pool, walletId) {
15902
+ const record = syncRecord(ctx, walletId);
15903
+ const { publicKey } = parseSyncKeyHeader(record.header);
15904
+ return pool.get(publicKey);
15905
+ }
15906
+ async function syncSign(ctx, pool, params, requestSession) {
15907
+ ctx.session.require(requestSession);
15908
+ if (params.event.kind !== 30078) {
15909
+ throw new KernelError("invalid-input", "sync signer authors kind-30078 events only");
15910
+ }
15911
+ const signer = requireSyncSigner(ctx, pool, params.walletId);
15912
+ return signEvent2(pool, signer.keys.publicKey, params.event);
15913
+ }
15914
+ async function syncEncrypt(ctx, pool, params, requestSession) {
15915
+ ctx.session.require(requestSession);
15916
+ const signer = requireSyncSigner(ctx, pool, params.walletId);
15917
+ const { publicKey } = signer.keys;
15918
+ return signer.nip44Encrypt(publicKey, params.text);
15919
+ }
15920
+ async function syncDecrypt(ctx, pool, params, requestSession) {
15921
+ ctx.session.require(requestSession);
15922
+ const signer = requireSyncSigner(ctx, pool, params.walletId);
15923
+ const { publicKey } = signer.keys;
15924
+ return signer.nip44Decrypt(publicKey, params.text);
15925
+ }
15926
+
16189
15927
  // ../wallet-kernel/src/modules/nostr/index.ts
16190
15928
  function createNostrModule(backend) {
16191
15929
  const pool = new SignerPool(backend);
15930
+ const syncPool = new SignerPool(backend);
16192
15931
  const vault = {
16193
- ownsRecord: (kind) => kind === NOSTR_KEY_KIND,
15932
+ ownsRecord: (kind) => kind === NOSTR_KEY_KIND || kind === NOSTR_SYNC_KEY_KIND,
16194
15933
  claimUnlocked: (records) => {
16195
15934
  const unclaimed = [];
16196
15935
  for (const record of records) {
@@ -16199,6 +15938,11 @@ function createNostrModule(backend) {
16199
15938
  if (claimed !== record.id) {
16200
15939
  throw new KernelError("integrity", "nostr key does not match its record", undefined, true);
16201
15940
  }
15941
+ } else if (record.kind === NOSTR_SYNC_KEY_KIND) {
15942
+ const claimed = syncPool.add(record.plaintext);
15943
+ if (claimed !== record.id) {
15944
+ throw new KernelError("integrity", "sync key does not match its record", undefined, true);
15945
+ }
16202
15946
  } else {
16203
15947
  unclaimed.push(record);
16204
15948
  }
@@ -16208,61 +15952,35 @@ function createNostrModule(backend) {
16208
15952
  forget: (kind, id) => {
16209
15953
  if (kind === NOSTR_KEY_KIND) {
16210
15954
  pool.remove(id);
15955
+ } else if (kind === NOSTR_SYNC_KEY_KIND) {
15956
+ syncPool.remove(id);
16211
15957
  }
16212
15958
  },
16213
15959
  lock: () => {
16214
15960
  pool.dispose();
15961
+ syncPool.dispose();
16215
15962
  },
16216
15963
  walletDeleteOps: (image, walletId) => {
16217
15964
  const ops = [];
16218
15965
  for (const record of image.records) {
16219
- if (record.kind !== NOSTR_KEY_KIND) {
16220
- continue;
16221
- }
16222
- const header = parseNostrKeyHeader(record.header);
16223
- if (header.origin === "derived" && header.walletId === walletId) {
16224
- ops.push({ op: "delete-record", kind: NOSTR_KEY_KIND, id: record.id });
15966
+ if (record.kind === NOSTR_KEY_KIND) {
15967
+ const header = parseNostrKeyHeader(record.header);
15968
+ if (header.walletId === walletId) {
15969
+ ops.push({ op: "delete-record", kind: NOSTR_KEY_KIND, id: record.id });
15970
+ }
15971
+ } else if (record.kind === NOSTR_SYNC_KEY_KIND) {
15972
+ const header = parseSyncKeyHeader(record.header);
15973
+ if (header.walletId === walletId) {
15974
+ ops.push({ op: "delete-record", kind: NOSTR_SYNC_KEY_KIND, id: record.id });
15975
+ }
16225
15976
  }
16226
15977
  }
16227
15978
  return ops;
16228
- },
16229
- backupSecrets: (image, dek) => {
16230
- const secrets = [];
16231
- for (const record of image.records) {
16232
- if (record.kind !== NOSTR_KEY_KIND) {
16233
- continue;
16234
- }
16235
- const header = parseNostrKeyHeader(record.header);
16236
- if (header.origin === "derived" || header.origin === "nip46-client") {
16237
- continue;
16238
- }
16239
- secrets.push(openRecord(dek, record));
16240
- }
16241
- return secrets;
16242
- },
16243
- backupRecords: (platform, image, dek, secrets, now) => {
16244
- const records = [];
16245
- for (const secretKey of secrets) {
16246
- const publicKey = getPublicKey(secretKey);
16247
- if (image.records.some((r) => r.kind === NOSTR_KEY_KIND && r.id === publicKey)) {
16248
- continue;
16249
- }
16250
- records.push(sealRecord(platform, dek, NOSTR_KEY_KIND, publicKey, encodeNostrKeyHeader({
16251
- publicKey,
16252
- origin: "nsec",
16253
- backedUp: true,
16254
- createdAt: now
16255
- }), secretKey));
16256
- }
16257
- return records;
16258
15979
  }
16259
15980
  };
16260
15981
  const handlers = {
16261
15982
  "nostr.discover": async (ctx, params, session) => discover(ctx, params, session),
16262
15983
  "nostr.deriveKey": async (ctx, params, session) => deriveKey2(ctx, params, session),
16263
- "nostr.importKey": async (ctx, params, session) => importKey(ctx, params, session),
16264
- "nostr.generateKey": async (ctx, params, session) => generateKey(ctx, params, session),
16265
- "nostr.createNip46ClientKey": async (ctx, _params, session) => createNip46ClientKey(ctx, session),
16266
15984
  "nostr.removeKey": async (ctx, params, session) => removeKey(ctx, params, session),
16267
15985
  "nostr.exportKey": async (ctx, params, session) => exportKey(ctx, params, session),
16268
15986
  "nostr.signEvent": async (ctx, params, session) => sign4(ctx, pool, params, session),
@@ -16270,7 +15988,11 @@ function createNostrModule(backend) {
16270
15988
  "nostr.nip04Decrypt": async (ctx, params, session) => nip04Decrypt(ctx, pool, params, session),
16271
15989
  "nostr.nip44Encrypt": async (ctx, params, session) => nip44Encrypt(ctx, pool, params, session),
16272
15990
  "nostr.nip44Decrypt": async (ctx, params, session) => nip44Decrypt(ctx, pool, params, session),
16273
- "nostr.unwrapGiftWraps": async (ctx, params, session) => unwrapGiftWraps(ctx, pool, params, session)
15991
+ "nostr.unwrapGiftWraps": async (ctx, params, session) => unwrapGiftWraps(ctx, pool, params, session),
15992
+ "nostr.syncKey": async (ctx, params, session) => syncKey(ctx, params, session),
15993
+ "nostr.syncSign": async (ctx, params, session) => syncSign(ctx, syncPool, params, session),
15994
+ "nostr.syncEncrypt": async (ctx, params, session) => syncEncrypt(ctx, syncPool, params, session),
15995
+ "nostr.syncDecrypt": async (ctx, params, session) => syncDecrypt(ctx, syncPool, params, session)
16274
15996
  };
16275
15997
  return {
16276
15998
  vault,
@@ -16454,228 +16176,241 @@ var decodeIntent = (rt, account, intent) => {
16454
16176
  }
16455
16177
  return result;
16456
16178
  };
16457
- function createSparkModule() {
16458
- const signers = new Map;
16459
- const approvals = new Map;
16460
- let backendPromise;
16461
- let runtimePromise;
16462
- const sparkRuntime = async () => {
16463
- runtimePromise ??= (async () => {
16464
- try {
16465
- return await loadSparkRuntime();
16466
- } catch (error) {
16467
- runtimePromise = undefined;
16468
- throw error instanceof KernelError ? error : new KernelError("unavailable", "spark runtime failed to load");
16469
- }
16470
- })();
16471
- return runtimePromise;
16472
- };
16473
- const liveApprovals = (ctx, key) => {
16474
- const now = ctx.platform.elapsed();
16475
- const live = (approvals.get(key) ?? []).filter((approval) => approval.deadline > now);
16476
- if (live.length === 0) {
16477
- approvals.delete(key);
16478
- } else {
16479
- approvals.set(key, live);
16480
- }
16481
- return live;
16482
- };
16483
- const backend = async (ctx) => {
16484
- backendPromise ??= (async () => {
16485
- try {
16486
- return await ctx.platform.backends.spark();
16487
- } catch (error) {
16488
- backendPromise = undefined;
16489
- throw error instanceof KernelError ? error : new KernelError("unavailable", "spark backend failed to load");
16490
- }
16491
- })();
16492
- return backendPromise;
16493
- };
16494
- const disposeAll = () => {
16495
- for (const signer of signers.values()) {
16496
- signer.dispose();
16497
- }
16498
- signers.clear();
16499
- approvals.clear();
16500
- };
16501
- const disposeWallet = (walletId) => {
16502
- for (const [key, signer] of signers) {
16503
- if (key.startsWith(`${walletId}/`)) {
16504
- signer.dispose();
16505
- signers.delete(key);
16506
- }
16507
- }
16508
- for (const key of approvals.keys()) {
16509
- if (key.startsWith(`${walletId}/`)) {
16510
- approvals.delete(key);
16511
- }
16512
- }
16513
- };
16514
- const poison = () => {
16515
- backendPromise = undefined;
16516
- disposeAll();
16517
- return new KernelError("unavailable", "spark backend was disposed after a wasm fault");
16518
- };
16519
- const mapError = (error) => {
16520
- if (error instanceof KernelError) {
16521
- return error;
16522
- }
16523
- if (isNamed(error, "WasmPoisonedError")) {
16524
- return poison();
16525
- }
16526
- if (isNamed(error, "SparkInputError")) {
16527
- return new KernelError("invalid-input", "spark signer rejected the request");
16528
- }
16529
- return new KernelError("integrity", "spark signer call failed");
16530
- };
16531
- const signerFor = async (ctx, account, requestSession) => {
16532
- const { dek } = ctx.session.require(requestSession);
16533
- const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === account.walletId);
16534
- if (record === undefined) {
16535
- disposeWallet(account.walletId);
16536
- throw new KernelError("not-found", "no such wallet");
16537
- }
16538
- const existing = signers.get(poolKey(account));
16539
- if (existing !== undefined) {
16540
- return existing;
16541
- }
16542
- const entropy = openRecord(dek, record);
16543
- const seed = await seedFromEntropy(entropy, ctx.platform.pbkdf2);
16544
- wipe(entropy);
16545
- let accountKey;
16546
- const rt = await sparkRuntime();
16179
+ var sparkRuntime = async (state) => {
16180
+ state.runtimePromise ??= (async () => {
16547
16181
  try {
16548
- accountKey = rt.sparkAccountKey(seed, account.network, account.network === "mainnet" ? account.groupIndex + 1 : account.groupIndex);
16182
+ return await loadSparkRuntime();
16549
16183
  } catch (error) {
16550
- throw mapError(error);
16551
- } finally {
16552
- wipe(seed);
16184
+ state.runtimePromise = undefined;
16185
+ throw error instanceof KernelError ? error : new KernelError("unavailable", "spark runtime failed to load");
16553
16186
  }
16554
- const crypto2 = await backend(ctx);
16187
+ })();
16188
+ return state.runtimePromise;
16189
+ };
16190
+ var liveApprovals = (state, ctx, key) => {
16191
+ const now = ctx.platform.elapsed();
16192
+ const live = (state.approvals.get(key) ?? []).filter((approval) => approval.deadline > now);
16193
+ if (live.length === 0) {
16194
+ state.approvals.delete(key);
16195
+ } else {
16196
+ state.approvals.set(key, live);
16197
+ }
16198
+ return live;
16199
+ };
16200
+ var backend = async (state, ctx) => {
16201
+ state.backendPromise ??= (async () => {
16555
16202
  try {
16556
- const signer = rt.createSparkSigner({
16557
- crypto: crypto2,
16558
- accountKey,
16559
- network: account.network,
16560
- random: ctx.platform.random,
16561
- authorize: async (outflow) => authorizeWithCtx(ctx, account, outflow)
16562
- });
16563
- signers.set(poolKey(account), signer);
16564
- return signer;
16203
+ return await ctx.platform.backends.spark();
16565
16204
  } catch (error) {
16566
- throw mapError(error);
16567
- } finally {
16568
- wipe(accountKey);
16205
+ state.backendPromise = undefined;
16206
+ throw error instanceof KernelError ? error : new KernelError("unavailable", "spark backend failed to load");
16569
16207
  }
16570
- };
16571
- const authorizeWithCtx = async (ctx, account, outflow) => {
16572
- const rt = await sparkRuntime();
16573
- if (outflow.kind === "swap") {
16574
- return;
16208
+ })();
16209
+ return state.backendPromise;
16210
+ };
16211
+ var disposeAll = (state) => {
16212
+ for (const signer of state.signers.values()) {
16213
+ signer.dispose();
16214
+ }
16215
+ state.signers.clear();
16216
+ state.approvals.clear();
16217
+ };
16218
+ var disposeWallet = (state, walletId) => {
16219
+ for (const [key, signer] of state.signers) {
16220
+ if (key.startsWith(`${walletId}/`)) {
16221
+ signer.dispose();
16222
+ state.signers.delete(key);
16575
16223
  }
16576
- const key = poolKey(account);
16577
- const live = liveApprovals(ctx, key);
16578
- for (const approval of live) {
16579
- const { intent } = approval;
16580
- if (outflow.kind === "transfer" && intent.kind === "transfer") {
16581
- const covered = outflow.receivers.every((receiver) => intent.receivers.some((wanted) => equalBytes(wanted.identityPublicKey, receiver.identityPublicKey) && receiver.amountSats <= wanted.amountSats));
16582
- if (covered) {
16583
- live.splice(live.indexOf(approval), 1);
16584
- return;
16585
- }
16586
- continue;
16587
- }
16588
- if (outflow.kind === "lightning" && intent.kind === "lightning") {
16589
- const signer = signers.get(key);
16590
- const { paymentHash } = approval.decoded;
16591
- const budget = approval.decoded.invoiceAmountSats;
16592
- if (signer === undefined || paymentHash === undefined || budget === undefined) {
16593
- continue;
16594
- }
16595
- const expected = rt.lightningSendHtlcScript({
16596
- paymentHash,
16597
- sspIdentityPublicKey: rt.sparkNetworkConfig(account.network).ssp.identityPublicKey,
16598
- identityPublicKey: await signer.identityPublicKey()
16599
- });
16600
- if (!equalBytes(expected, outflow.htlcOutputScript)) {
16601
- continue;
16602
- }
16603
- const fresh = outflow.leaves.filter((leaf) => !approval.spentLeaves.has(bytesToHex(leaf.publicKey)));
16604
- const total = fresh.reduce((sum, leaf) => sum + leaf.amountSats, 0) + [...approval.spentLeaves.values()].reduce((sum, v) => sum + v, 0);
16605
- if (total > budget + intent.maxFeeSats) {
16606
- continue;
16607
- }
16608
- for (const leaf of fresh) {
16609
- approval.spentLeaves.set(bytesToHex(leaf.publicKey), leaf.amountSats);
16610
- }
16611
- return;
16612
- }
16613
- if (outflow.kind === "exit" && intent.kind === "exit") {
16614
- const { addressScript } = approval.decoded;
16615
- if (addressScript === undefined) {
16616
- continue;
16617
- }
16618
- const pays = outflow.exitOutputs.some((output) => equalBytes(output.script, addressScript) && output.amountSats >= intent.amountSats);
16619
- if (!pays) {
16620
- continue;
16621
- }
16622
- const fresh = outflow.leaves.filter((leaf) => !approval.spentLeaves.has(bytesToHex(leaf.publicKey)));
16623
- const total = fresh.reduce((sum, leaf) => sum + leaf.amountSats, 0) + [...approval.spentLeaves.values()].reduce((sum, v) => sum + v, 0);
16624
- if (total > intent.amountSats + intent.maxFeeSats) {
16625
- continue;
16626
- }
16627
- for (const leaf of fresh) {
16628
- approval.spentLeaves.set(bytesToHex(leaf.publicKey), leaf.amountSats);
16629
- }
16630
- return;
16631
- }
16632
- if (outflow.kind === "onchain" && intent.kind === "onchain") {
16633
- const { addressScript } = approval.decoded;
16634
- if (addressScript === undefined) {
16635
- continue;
16636
- }
16637
- const every = outflow.outputs.every((output) => equalBytes(output.script, rt.EPHEMERAL_ANCHOR_SCRIPT) || equalBytes(output.script, addressScript));
16638
- if (!every) {
16639
- continue;
16640
- }
16641
- const fee = outflow.inputSats - outflow.totalSats;
16642
- if (fee > intent.maxFeeSats) {
16643
- continue;
16644
- }
16645
- live.splice(live.indexOf(approval), 1);
16646
- return;
16647
- }
16648
- if (outflow.kind === "token" && intent.kind === "token") {
16649
- const signer = signers.get(key);
16650
- if (signer === undefined) {
16651
- continue;
16652
- }
16653
- const identity = await signer.identityPublicKey();
16654
- const covered = outflow.outputs.every((output) => {
16655
- if (equalBytes(output.ownerPublicKey, identity)) {
16656
- return true;
16657
- }
16658
- if (!equalBytes(output.tokenIdentifier, intent.tokenIdentifier)) {
16659
- return false;
16660
- }
16661
- return intent.receivers.some((wanted) => equalBytes(wanted.ownerPublicKey, output.ownerPublicKey) && output.amount <= BigInt(wanted.amount));
16662
- });
16663
- if (!covered) {
16664
- continue;
16665
- }
16666
- live.splice(live.indexOf(approval), 1);
16667
- return;
16668
- }
16224
+ }
16225
+ for (const key of state.approvals.keys()) {
16226
+ if (key.startsWith(`${walletId}/`)) {
16227
+ state.approvals.delete(key);
16669
16228
  }
16670
- throw approvalRequired();
16671
- };
16672
- const call = async (ctx, account, requestSession, run) => {
16673
- const signer = await signerFor(ctx, account, requestSession);
16674
- try {
16675
- return await run(signer);
16676
- } catch (error) {
16677
- throw mapError(error);
16229
+ }
16230
+ };
16231
+ var poison = (state) => {
16232
+ state.backendPromise = undefined;
16233
+ disposeAll(state);
16234
+ return new KernelError("unavailable", "spark backend was disposed after a wasm fault");
16235
+ };
16236
+ var mapError = (state, error) => {
16237
+ if (error instanceof KernelError) {
16238
+ return error;
16239
+ }
16240
+ if (isNamed(error, "WasmPoisonedError")) {
16241
+ return poison(state);
16242
+ }
16243
+ if (isNamed(error, "SparkInputError")) {
16244
+ return new KernelError("invalid-input", "spark signer rejected the request");
16245
+ }
16246
+ return new KernelError("integrity", "spark signer call failed");
16247
+ };
16248
+ var signerFor = async (state, ctx, account, requestSession) => {
16249
+ const { dek } = ctx.session.require(requestSession);
16250
+ const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === account.walletId);
16251
+ if (record === undefined) {
16252
+ disposeWallet(state, account.walletId);
16253
+ throw new KernelError("not-found", "no such wallet");
16254
+ }
16255
+ const existing = state.signers.get(poolKey(account));
16256
+ if (existing !== undefined) {
16257
+ return existing;
16258
+ }
16259
+ let accountKey;
16260
+ const rt = await sparkRuntime(state);
16261
+ try {
16262
+ accountKey = await withWalletSeed(ctx.platform.pbkdf2, dek, record, (seed) => rt.sparkAccountKey(seed, account.network, account.network === "mainnet" ? account.groupIndex + 1 : account.groupIndex));
16263
+ } catch (error) {
16264
+ throw mapError(state, error);
16265
+ }
16266
+ const crypto2 = await backend(state, ctx);
16267
+ try {
16268
+ const signer = rt.createSparkSigner({
16269
+ crypto: crypto2,
16270
+ accountKey,
16271
+ network: account.network,
16272
+ random: ctx.platform.random,
16273
+ authorize: async (outflow) => authorizeWithCtx(state, ctx, account, outflow)
16274
+ });
16275
+ state.signers.set(poolKey(account), signer);
16276
+ return signer;
16277
+ } catch (error) {
16278
+ throw mapError(state, error);
16279
+ } finally {
16280
+ wipe(accountKey);
16281
+ }
16282
+ };
16283
+ var transferCovered = (outflow, intent) => outflow.receivers.every((receiver) => intent.receivers.some((wanted) => equalBytes(wanted.identityPublicKey, receiver.identityPublicKey) && receiver.amountSats <= wanted.amountSats));
16284
+ var lightningCovered = async (state, rt, key, network, outflow, approval, intent) => {
16285
+ const signer = state.signers.get(key);
16286
+ const { paymentHash } = approval.decoded;
16287
+ const budget = approval.decoded.invoiceAmountSats;
16288
+ if (signer === undefined || paymentHash === undefined || budget === undefined) {
16289
+ return false;
16290
+ }
16291
+ const expected = rt.lightningSendHtlcScript({
16292
+ paymentHash,
16293
+ sspIdentityPublicKey: rt.sparkNetworkConfig(network).ssp.identityPublicKey,
16294
+ identityPublicKey: await signer.identityPublicKey()
16295
+ });
16296
+ if (!equalBytes(expected, outflow.htlcOutputScript)) {
16297
+ return false;
16298
+ }
16299
+ const fresh = outflow.leaves.filter((leaf) => !approval.spentLeaves.has(bytesToHex(leaf.publicKey)));
16300
+ const total = fresh.reduce((sum, leaf) => sum + leaf.amountSats, 0) + [...approval.spentLeaves.values()].reduce((sum, v) => sum + v, 0);
16301
+ if (total > budget + intent.maxFeeSats) {
16302
+ return false;
16303
+ }
16304
+ for (const leaf of fresh) {
16305
+ approval.spentLeaves.set(bytesToHex(leaf.publicKey), leaf.amountSats);
16306
+ }
16307
+ return true;
16308
+ };
16309
+ var exitCovered = (outflow, approval, intent) => {
16310
+ const { addressScript } = approval.decoded;
16311
+ if (addressScript === undefined) {
16312
+ return false;
16313
+ }
16314
+ const pays = outflow.exitOutputs.some((output) => equalBytes(output.script, addressScript) && output.amountSats >= intent.amountSats);
16315
+ if (!pays) {
16316
+ return false;
16317
+ }
16318
+ const fresh = outflow.leaves.filter((leaf) => !approval.spentLeaves.has(bytesToHex(leaf.publicKey)));
16319
+ const total = fresh.reduce((sum, leaf) => sum + leaf.amountSats, 0) + [...approval.spentLeaves.values()].reduce((sum, v) => sum + v, 0);
16320
+ if (total > intent.amountSats + intent.maxFeeSats) {
16321
+ return false;
16322
+ }
16323
+ for (const leaf of fresh) {
16324
+ approval.spentLeaves.set(bytesToHex(leaf.publicKey), leaf.amountSats);
16325
+ }
16326
+ return true;
16327
+ };
16328
+ var onchainCovered = (rt, outflow, approval, intent) => {
16329
+ const { addressScript } = approval.decoded;
16330
+ if (addressScript === undefined) {
16331
+ return false;
16332
+ }
16333
+ const every = outflow.outputs.every((output) => equalBytes(output.script, rt.EPHEMERAL_ANCHOR_SCRIPT) || equalBytes(output.script, addressScript));
16334
+ if (!every) {
16335
+ return false;
16336
+ }
16337
+ const fee = outflow.inputSats - outflow.totalSats;
16338
+ return fee <= intent.maxFeeSats;
16339
+ };
16340
+ var tokenCovered = async (state, key, outflow, intent) => {
16341
+ const signer = state.signers.get(key);
16342
+ if (signer === undefined) {
16343
+ return false;
16344
+ }
16345
+ const identity = await signer.identityPublicKey();
16346
+ return outflow.outputs.every((output) => {
16347
+ if (equalBytes(output.ownerPublicKey, identity)) {
16348
+ return true;
16349
+ }
16350
+ if (!equalBytes(output.tokenIdentifier, intent.tokenIdentifier)) {
16351
+ return false;
16352
+ }
16353
+ return intent.receivers.some((wanted) => equalBytes(wanted.ownerPublicKey, output.ownerPublicKey) && output.amount <= BigInt(wanted.amount));
16354
+ });
16355
+ };
16356
+ var authorizeWithCtx = async (state, ctx, account, outflow) => {
16357
+ const rt = await sparkRuntime(state);
16358
+ if (outflow.kind === "swap") {
16359
+ return;
16360
+ }
16361
+ const key = poolKey(account);
16362
+ const live = liveApprovals(state, ctx, key);
16363
+ for (const approval of live) {
16364
+ const { intent } = approval;
16365
+ const covered = outflow.kind === "transfer" && intent.kind === "transfer" ? transferCovered(outflow, intent) : outflow.kind === "lightning" && intent.kind === "lightning" ? await lightningCovered(state, rt, key, account.network, outflow, approval, intent) : outflow.kind === "exit" && intent.kind === "exit" ? exitCovered(outflow, approval, intent) : outflow.kind === "onchain" && intent.kind === "onchain" ? onchainCovered(rt, outflow, approval, intent) : outflow.kind === "token" && intent.kind === "token" ? await tokenCovered(state, key, outflow, intent) : false;
16366
+ if (covered) {
16367
+ live.splice(live.indexOf(approval), 1);
16368
+ return;
16678
16369
  }
16370
+ }
16371
+ throw approvalRequired();
16372
+ };
16373
+ var call = async (state, ctx, account, requestSession, run) => {
16374
+ const signer = await signerFor(state, ctx, account, requestSession);
16375
+ try {
16376
+ return await run(signer);
16377
+ } catch (error) {
16378
+ throw mapError(state, error);
16379
+ }
16380
+ };
16381
+ var sparkApprove = async (state, ctx, params, session) => {
16382
+ const { dek } = ctx.session.require(session);
16383
+ const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === params.account.walletId);
16384
+ if (record === undefined) {
16385
+ throw new KernelError("not-found", "no such wallet");
16386
+ }
16387
+ const key = poolKey(params.account);
16388
+ if (liveApprovals(state, ctx, key).length >= APPROVAL_MAX_PER_ACCOUNT) {
16389
+ throw new KernelError("invalid-input", "approval cap reached for this account");
16390
+ }
16391
+ const { summary, decoded } = decodeIntent(await sparkRuntime(state), params.account, params.intent);
16392
+ await verifyFactor(ctx.platform, ctx.image, params.verify, dek, () => sparkPrompt(promptLocale(ctx.platform.keystore?.locale ?? "en"), summary));
16393
+ ctx.session.require(session);
16394
+ const live = liveApprovals(state, ctx, key);
16395
+ if (live.length >= APPROVAL_MAX_PER_ACCOUNT) {
16396
+ throw new KernelError("invalid-input", "approval cap reached for this account");
16397
+ }
16398
+ live.push({
16399
+ intent: params.intent,
16400
+ deadline: ctx.platform.elapsed() + APPROVAL_TTL_MS,
16401
+ decoded,
16402
+ summary,
16403
+ spentLeaves: new Map
16404
+ });
16405
+ state.approvals.set(key, live);
16406
+ return summary;
16407
+ };
16408
+ function createSparkModule() {
16409
+ const state = {
16410
+ signers: new Map,
16411
+ approvals: new Map,
16412
+ backendPromise: undefined,
16413
+ runtimePromise: undefined
16679
16414
  };
16680
16415
  const vault = {
16681
16416
  ownsRecord: () => false,
@@ -16684,56 +16419,28 @@ function createSparkModule() {
16684
16419
  return;
16685
16420
  },
16686
16421
  lock: () => {
16687
- disposeAll();
16422
+ disposeAll(state);
16688
16423
  },
16689
- backupSecrets: () => [],
16690
- backupRecords: () => [],
16691
16424
  walletDeleteOps: (_image, walletId) => {
16692
- disposeWallet(walletId);
16425
+ disposeWallet(state, walletId);
16693
16426
  return [];
16694
16427
  }
16695
16428
  };
16696
16429
  const handlers = {
16697
- "spark.identityPublicKey": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.identityPublicKey()),
16698
- "spark.publicKeys": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.publicKeys(params.keys)),
16699
- "spark.receivedPublicKeys": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.receivedPublicKeys(params.ciphertexts)),
16700
- "spark.newCommitments": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.newCommitments(params.count)),
16701
- "spark.signFrost": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.signFrost(params.jobs)),
16702
- "spark.aggregateFrost": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.aggregateFrost(params.jobs)),
16703
- "spark.signIdentity": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.signIdentity(params.statement)),
16704
- "spark.signKeySpend": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.signKeySpend(params.key, params.target)),
16705
- "spark.signHtlcTimeout": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.signHtlcTimeout(params.request)),
16706
- "spark.prepareTransfer": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.prepareTransfer(params.request)),
16707
- "spark.prepareClaim": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.prepareClaim(params.request)),
16708
- "spark.prepareLightningReceive": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.prepareLightningReceive()),
16709
- "spark.claimStaticDeposit": async (ctx, params, session) => call(ctx, params.account, session, async (signer) => signer.claimStaticDeposit(params.request)),
16710
- "spark.approve": async (ctx, params, session) => {
16711
- const { dek } = ctx.session.require(session);
16712
- const record = ctx.image.records.find((entry) => entry.kind === "entropy" && entry.id === params.account.walletId);
16713
- if (record === undefined) {
16714
- throw new KernelError("not-found", "no such wallet");
16715
- }
16716
- const key = poolKey(params.account);
16717
- if (liveApprovals(ctx, key).length >= APPROVAL_MAX_PER_ACCOUNT) {
16718
- throw new KernelError("invalid-input", "approval cap reached for this account");
16719
- }
16720
- const { summary, decoded } = decodeIntent(await sparkRuntime(), params.account, params.intent);
16721
- await verifyFactor(ctx.platform, ctx.image, params.verify, dek, () => sparkPrompt(promptLocale(ctx.platform.keystore?.locale ?? "en"), summary));
16722
- ctx.session.require(session);
16723
- const live = liveApprovals(ctx, key);
16724
- if (live.length >= APPROVAL_MAX_PER_ACCOUNT) {
16725
- throw new KernelError("invalid-input", "approval cap reached for this account");
16726
- }
16727
- live.push({
16728
- intent: params.intent,
16729
- deadline: ctx.platform.elapsed() + APPROVAL_TTL_MS,
16730
- decoded,
16731
- summary,
16732
- spentLeaves: new Map
16733
- });
16734
- approvals.set(key, live);
16735
- return summary;
16736
- }
16430
+ "spark.identityPublicKey": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.identityPublicKey()),
16431
+ "spark.publicKeys": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.publicKeys(params.keys)),
16432
+ "spark.receivedPublicKeys": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.receivedPublicKeys(params.ciphertexts)),
16433
+ "spark.newCommitments": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.newCommitments(params.count)),
16434
+ "spark.signFrost": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.signFrost(params.jobs)),
16435
+ "spark.aggregateFrost": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.aggregateFrost(params.jobs)),
16436
+ "spark.signIdentity": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.signIdentity(params.statement)),
16437
+ "spark.signKeySpend": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.signKeySpend(params.key, params.target)),
16438
+ "spark.signHtlcTimeout": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.signHtlcTimeout(params.request)),
16439
+ "spark.prepareTransfer": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.prepareTransfer(params.request)),
16440
+ "spark.prepareClaim": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.prepareClaim(params.request)),
16441
+ "spark.prepareLightningReceive": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.prepareLightningReceive()),
16442
+ "spark.claimStaticDeposit": async (ctx, params, session) => call(state, ctx, params.account, session, async (signer) => signer.claimStaticDeposit(params.request)),
16443
+ "spark.approve": async (ctx, params, session) => sparkApprove(state, ctx, params, session)
16737
16444
  };
16738
16445
  return { vault, handlers };
16739
16446
  }
@@ -17516,17 +17223,6 @@ function createIndexedDbStore() {
17516
17223
  };
17517
17224
  }
17518
17225
 
17519
- // src/worker/spark.ts
17520
- async function loadSparkBackend(readWasm) {
17521
- const { loadSparkWasm, SPARK_WASM_INTEGRITY } = await (__preload("1vpxmqwn"), import("./browser-1vpxmqwn.js"));
17522
- const bytes = await readWasm();
17523
- const integrity = `sha256-${base64.encode(sha256(bytes))}`;
17524
- if (integrity !== SPARK_WASM_INTEGRITY) {
17525
- throw new KernelError("integrity", "spark.wasm failed the integrity check");
17526
- }
17527
- return loadSparkWasm({ module: bytes });
17528
- }
17529
-
17530
17226
  // src/worker/subtle.ts
17531
17227
  var SUBTLE_HASH = {
17532
17228
  sha256: "SHA-256",
@@ -17544,6 +17240,33 @@ var subtlePbkdf2 = async (hash, password, salt, iterations, length) => {
17544
17240
  }
17545
17241
  };
17546
17242
 
17243
+ // src/worker/platform.ts
17244
+ var basePlatform = () => ({
17245
+ random: (length) => crypto.getRandomValues(new Uint8Array(length)),
17246
+ now: () => Date.now(),
17247
+ elapsed: () => performance.now(),
17248
+ setTimer: (delayMs, fn) => {
17249
+ const timer = setTimeout(fn, delayMs);
17250
+ return () => {
17251
+ clearTimeout(timer);
17252
+ };
17253
+ },
17254
+ pbkdf2: subtlePbkdf2,
17255
+ keystore: undefined,
17256
+ passkey: undefined
17257
+ });
17258
+
17259
+ // src/worker/spark.ts
17260
+ async function loadSparkBackend(readWasm) {
17261
+ const { loadSparkWasm, SPARK_WASM_INTEGRITY } = await (__preload("1vpxmqwn"), import("./browser-1vpxmqwn.js"));
17262
+ const bytes = await readWasm();
17263
+ const integrity = `sha256-${base64.encode(sha256(bytes))}`;
17264
+ if (integrity !== SPARK_WASM_INTEGRITY) {
17265
+ throw new KernelError("integrity", "spark.wasm failed the integrity check");
17266
+ }
17267
+ return loadSparkWasm({ module: bytes });
17268
+ }
17269
+
17547
17270
  // src/worker/worker.ts
17548
17271
  var onInit = (event) => {
17549
17272
  const { data } = event;
@@ -17552,19 +17275,8 @@ var onInit = (event) => {
17552
17275
  }
17553
17276
  removeEventListener("message", onInit);
17554
17277
  const platform = {
17555
- random: (length) => crypto.getRandomValues(new Uint8Array(length)),
17556
- now: () => Date.now(),
17557
- elapsed: () => performance.now(),
17558
- setTimer: (delayMs, fn) => {
17559
- const timer = setTimeout(fn, delayMs);
17560
- return () => {
17561
- clearTimeout(timer);
17562
- };
17563
- },
17564
- pbkdf2: subtlePbkdf2,
17278
+ ...basePlatform(),
17565
17279
  store: createIndexedDbStore(),
17566
- keystore: undefined,
17567
- passkey: undefined,
17568
17280
  policy: {
17569
17281
  idle: { ms: idleMsOf(data.idleMinutes), activity: "presence" },
17570
17282
  maxSessionMs: MAX_SESSION_MS,