@naculus/connect-appkit-core 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -20,31 +20,74 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ DEFAULT_NOTIFICATION_SETTINGS: () => DEFAULT_NOTIFICATION_SETTINGS,
24
+ InvalidUserOperationReceiptError: () => InvalidUserOperationReceiptError,
25
+ NOTIFICATION_SETTINGS_KEY: () => NOTIFICATION_SETTINGS_KEY,
23
26
  __resetResolverForTests: () => __resetResolverForTests,
27
+ addInAppNotification: () => addInAppNotification,
28
+ assertHexSignature: () => assertHexSignature,
24
29
  atomicSupportFor: () => atomicSupportFor,
30
+ bareEvmAddress: () => bareEvmAddress,
31
+ buildDelegationPolicyMessage: () => buildDelegationPolicyMessage,
32
+ buildSmartAccountConfig: () => buildSmartAccountConfig,
25
33
  chainNamespace: () => chainNamespace,
26
34
  chainNumber: () => chainNumber,
27
35
  chainsForNamespace: () => chainsForNamespace,
36
+ channelsUpdate: () => channelsUpdate,
37
+ clearOneInAppNotification: () => clearOneInAppNotification,
38
+ compareCostsKey: () => compareCostsKey,
28
39
  createDecimalsCache: () => createDecimalsCache,
40
+ createDelegationPolicyFlow: () => createDelegationPolicyFlow,
41
+ createNotification: () => createNotification,
42
+ createNotificationSettingsStorage: () => createNotificationSettingsStorage,
29
43
  decodeRevertReason: () => decodeRevertReason,
44
+ defaultSiwxDomain: () => defaultSiwxDomain,
45
+ defaultSiwxUri: () => defaultSiwxUri,
30
46
  describeChain: () => describeChain,
31
47
  eip155ChainIdToNumber: () => eip155ChainIdToNumber,
48
+ encodeErc20Approve: () => encodeErc20Approve,
49
+ encodeErc20Transfer: () => encodeErc20Transfer,
50
+ encodeErc20TransferFrom: () => encodeErc20TransferFrom,
51
+ fetchUserOperationReceipt: () => fetchUserOperationReceipt,
32
52
  getResolver: () => getResolver,
53
+ getSharedSessionKeyManager: () => getSharedSessionKeyManager,
33
54
  initialWeb3State: () => initialWeb3State,
55
+ isBurnDestination: () => isBurnDestination,
34
56
  isEvmChainId: () => isEvmChainId,
57
+ isPositiveIntegerAmount: () => isPositiveIntegerAmount,
58
+ isQuotableInput: () => isQuotableInput,
59
+ isSiwxExpired: () => isSiwxExpired,
60
+ isSiwxNotBeforeValid: () => isSiwxNotBeforeValid,
61
+ isVerifiablePolicy: () => isVerifiablePolicy,
62
+ loadNotificationSettings: () => loadNotificationSettings,
63
+ mutedChainSettings: () => mutedChainSettings,
35
64
  normalizeCapabilities: () => normalizeCapabilities,
36
65
  normalizeEip155ChainId: () => normalizeEip155ChainId,
66
+ parseUserOperationReceipt: () => parseUserOperationReceipt,
37
67
  readDecimals: () => readDecimals,
38
68
  readSolanaRoles: () => readSolanaRoles,
69
+ resetSharedSessionKeyManager: () => resetSharedSessionKeyManager,
39
70
  resolveChain: () => resolveChain,
71
+ resolveContextSimulationEndpoint: () => resolveContextSimulationEndpoint,
40
72
  resolveEvmChainId: () => resolveEvmChainId,
41
73
  resolveRevertReason: () => resolveRevertReason,
74
+ resolveSimulationEndpoint: () => resolveSimulationEndpoint,
75
+ resolveUserOpChain: () => resolveUserOpChain,
76
+ sameExecutionIntent: () => sameExecutionIntent,
77
+ saveNotificationSettings: () => saveNotificationSettings,
42
78
  selectChainCapabilities: () => selectChainCapabilities,
79
+ sessionKeyConfigFingerprint: () => sessionKeyConfigFingerprint,
80
+ simulateTransactionPreview: () => simulateTransactionPreview,
81
+ siwxResultToSession: () => siwxResultToSession,
43
82
  toChainSwitchError: () => toChainSwitchError,
44
83
  toEip155Accounts: () => toEip155Accounts,
84
+ toExecuteRouteError: () => toExecuteRouteError,
45
85
  toViemChain: () => toViemChain,
46
86
  tokenChainMismatch: () => tokenChainMismatch,
47
87
  tokenKey: () => tokenKey,
88
+ updateNotificationSettings: () => updateNotificationSettings,
89
+ validateDestination: () => validateDestination,
90
+ validateRouteRecipient: () => validateRouteRecipient,
48
91
  web3Reducer: () => web3Reducer,
49
92
  withRetry: () => withRetry,
50
93
  withTimeout: () => withTimeout,
@@ -192,8 +235,34 @@ function writeDecimals(cache, token, value) {
192
235
  cache.value = value;
193
236
  }
194
237
 
195
- // src/provider-errors.ts
238
+ // src/erc20-calldata.ts
196
239
  var import_connect_core5 = require("@naculus/connect-core");
240
+ var UINT256_MAX = (1n << 256n) - 1n;
241
+ var EVM_ADDRESS = /^0x[0-9a-fA-F]{40}$/;
242
+ function addressWord(address) {
243
+ if (typeof address !== "string" || !EVM_ADDRESS.test(address) || address !== address.toLowerCase() && !(0, import_connect_core5.isChecksumAddress)(address)) {
244
+ throw new TypeError("Invalid EVM address checksum");
245
+ }
246
+ return address.slice(2).toLowerCase().padStart(64, "0");
247
+ }
248
+ function uint256Word(value) {
249
+ if (typeof value !== "bigint" || value < 0n || value > UINT256_MAX) {
250
+ throw new RangeError("Amount must be a uint256 bigint");
251
+ }
252
+ return value.toString(16).padStart(64, "0");
253
+ }
254
+ function encodeErc20Transfer(to, amount) {
255
+ return `0xa9059cbb${addressWord(to)}${uint256Word(amount)}`;
256
+ }
257
+ function encodeErc20Approve(spender, amount) {
258
+ return `0x095ea7b3${addressWord(spender)}${uint256Word(amount)}`;
259
+ }
260
+ function encodeErc20TransferFrom(from, to, amount) {
261
+ return `0x23b872dd${addressWord(from)}${addressWord(to)}${uint256Word(amount)}`;
262
+ }
263
+
264
+ // src/provider-errors.ts
265
+ var import_connect_core6 = require("@naculus/connect-core");
197
266
  var USER_REJECTED = 4001;
198
267
  var UNRECOGNIZED_CHAIN = 4902;
199
268
  function providerCode(error) {
@@ -205,19 +274,19 @@ function providerCode(error) {
205
274
  return nested ? providerCode(nested) : void 0;
206
275
  }
207
276
  function toChainSwitchError(error, fallback = "chain_unsupported") {
208
- if (error instanceof import_connect_core5.WalletError) return error;
277
+ if (error instanceof import_connect_core6.WalletError) return error;
209
278
  const message = error instanceof Error ? error.message : "Unknown error during chain switch";
210
279
  switch (providerCode(error)) {
211
280
  case USER_REJECTED:
212
- return new import_connect_core5.WalletError("chain_switch_rejected", message, error);
281
+ return new import_connect_core6.WalletError("chain_switch_rejected", message, error);
213
282
  case UNRECOGNIZED_CHAIN:
214
- return new import_connect_core5.WalletError(
283
+ return new import_connect_core6.WalletError(
215
284
  "chain_unsupported",
216
285
  `${message} (the wallet does not have this chain configured)`,
217
286
  error
218
287
  );
219
288
  default:
220
- return new import_connect_core5.WalletError(fallback, message, error);
289
+ return new import_connect_core6.WalletError(fallback, message, error);
221
290
  }
222
291
  }
223
292
 
@@ -265,20 +334,834 @@ function resolveRevertReason(data, fallbackMessage) {
265
334
  return decodeRevertReason(data) ?? (fallbackMessage.includes("revert") ? fallbackMessage : "Transaction reverted");
266
335
  }
267
336
 
337
+ // src/simulation-endpoint.ts
338
+ var import_connect_core7 = require("@naculus/connect-core");
339
+ function resolveSimulationEndpoint(requestedChainId, fallbackChainId, requestedRpcUrl, fallbackRpcUrl) {
340
+ const chainId = requestedChainId ?? fallbackChainId;
341
+ if (chainId === void 0) {
342
+ throw new import_connect_core7.WalletError(
343
+ "invalid_chain",
344
+ "No chain to simulate on. Connect a wallet or pass a chainId."
345
+ );
346
+ }
347
+ if (requestedChainId !== void 0 && fallbackChainId !== void 0 && requestedChainId !== fallbackChainId && requestedRpcUrl === void 0) {
348
+ throw new import_connect_core7.WalletError(
349
+ "invalid_chain",
350
+ "Simulation chain override requires an RPC URL for that chain."
351
+ );
352
+ }
353
+ return { chainId, rpcUrl: requestedRpcUrl ?? fallbackRpcUrl };
354
+ }
355
+ function resolveContextSimulationEndpoint(requestedChainId, currentChain) {
356
+ const contextChainId = currentChain ? chainNumber(currentChain) ?? void 0 : void 0;
357
+ if (requestedChainId !== void 0 && currentChain && requestedChainId !== contextChainId) {
358
+ throw new import_connect_core7.WalletError(
359
+ "invalid_chain",
360
+ "Simulation chain does not match the connected chain endpoint."
361
+ );
362
+ }
363
+ return resolveSimulationEndpoint(
364
+ requestedChainId,
365
+ contextChainId,
366
+ void 0,
367
+ currentChain?.rpcUrl
368
+ );
369
+ }
370
+
371
+ // src/transaction-simulation.ts
372
+ var import_connect_core8 = require("@naculus/connect-core");
373
+ var coverage = {
374
+ balanceChanges: false,
375
+ approvalChanges: false,
376
+ risk: false
377
+ };
378
+ function baseResult(status, summary, changesDetected, warnings = []) {
379
+ return {
380
+ status,
381
+ coverage,
382
+ balanceChanges: [],
383
+ approvalChanges: [],
384
+ riskAssessment: { level: "unknown", score: 0, warnings },
385
+ provider: "eth_call",
386
+ summary,
387
+ changesDetected
388
+ };
389
+ }
390
+ async function simulateTransactionPreview(tx, context) {
391
+ if (!tx)
392
+ return baseResult("unavailable", "No transaction to simulate", false);
393
+ const { chainId, rpcUrl } = resolveContextSimulationEndpoint(
394
+ context.chainId,
395
+ context.currentChain
396
+ );
397
+ const from = context.evmAccount?.includes(":") ? context.evmAccount.split(":").pop() : context.evmAccount;
398
+ if (context.publicClient) {
399
+ if (context.publicClient.chain?.id !== chainId) {
400
+ throw new import_connect_core8.WalletError(
401
+ "invalid_chain",
402
+ "Simulation client chain does not match the requested chain."
403
+ );
404
+ }
405
+ try {
406
+ await context.publicClient.call({
407
+ to: tx.to,
408
+ data: tx.data ?? "0x",
409
+ value: tx.value ? BigInt(tx.value) : 0n,
410
+ ...from ? { from } : {}
411
+ });
412
+ return {
413
+ ...baseResult(
414
+ "success",
415
+ "Transaction simulation succeeded (basic revert check only)",
416
+ true
417
+ ),
418
+ gasInfo: tx.gas ? { gasLimit: BigInt(tx.gas), estimatedFeeEth: "0" } : void 0
419
+ };
420
+ } catch (cause) {
421
+ const error = cause;
422
+ const reason = resolveRevertReason(
423
+ error?.data ?? error?.cause?.data,
424
+ error?.message ?? String(cause)
425
+ );
426
+ return {
427
+ ...baseResult(
428
+ "reverted",
429
+ reason ? `Transaction reverted: ${reason}` : "Transaction reverted",
430
+ false,
431
+ [
432
+ {
433
+ category: "simulation_failed",
434
+ severity: "high",
435
+ message: reason ? `Transaction would revert: ${reason}` : "Transaction would revert"
436
+ }
437
+ ]
438
+ ),
439
+ revertReason: reason
440
+ };
441
+ }
442
+ }
443
+ if (!rpcUrl) {
444
+ return baseResult(
445
+ "unavailable",
446
+ "Simulation unavailable: no RPC URL",
447
+ false,
448
+ [
449
+ {
450
+ category: "simulation_failed",
451
+ severity: "low",
452
+ message: "No RPC URL or public client available for simulation"
453
+ }
454
+ ]
455
+ );
456
+ }
457
+ try {
458
+ const response = await (context.fetcher ?? fetch)(rpcUrl, {
459
+ method: "POST",
460
+ headers: { "Content-Type": "application/json" },
461
+ body: JSON.stringify({
462
+ jsonrpc: "2.0",
463
+ id: Date.now(),
464
+ method: "eth_call",
465
+ params: [
466
+ {
467
+ to: tx.to,
468
+ from,
469
+ data: tx.data ?? "0x",
470
+ value: tx.value ?? "0x0"
471
+ },
472
+ "latest"
473
+ ]
474
+ })
475
+ });
476
+ const json = await response.json();
477
+ if (json.error) {
478
+ return baseResult("reverted", "Transaction reverted", false, [
479
+ {
480
+ category: "simulation_failed",
481
+ severity: "high",
482
+ message: `Transaction would revert: ${json.error.message}`
483
+ }
484
+ ]);
485
+ }
486
+ return baseResult("success", "Transaction simulation succeeded", true);
487
+ } catch (cause) {
488
+ const error = cause;
489
+ return baseResult(
490
+ "unavailable",
491
+ "Simulation unavailable due to network error",
492
+ false,
493
+ [
494
+ {
495
+ category: "simulation_failed",
496
+ severity: "medium",
497
+ message: `Network error: ${error?.message ?? "Unknown"}`
498
+ }
499
+ ]
500
+ );
501
+ }
502
+ }
503
+
268
504
  // src/name-resolver.ts
269
- var import_connect_core6 = require("@naculus/connect-core");
505
+ var import_connect_core9 = require("@naculus/connect-core");
270
506
  var sharedResolver = null;
271
507
  function getResolver(config) {
272
- if (config) return new import_connect_core6.NameResolver(config);
273
- if (!sharedResolver) sharedResolver = new import_connect_core6.NameResolver();
508
+ if (config) return new import_connect_core9.NameResolver(config);
509
+ if (!sharedResolver) sharedResolver = new import_connect_core9.NameResolver();
274
510
  return sharedResolver;
275
511
  }
276
512
  function __resetResolverForTests() {
277
513
  sharedResolver = null;
278
514
  }
279
515
 
516
+ // src/notification.ts
517
+ var import_connect_core10 = require("@naculus/connect-core");
518
+ var NOTIFICATION_SETTINGS_KEY = "naculus_notif_react_settings";
519
+ var DEFAULT_NOTIFICATION_SETTINGS = {
520
+ telegram: false,
521
+ webpush: false,
522
+ inapp: true,
523
+ frequency: "final-only",
524
+ mutedChains: [],
525
+ mutedTypes: []
526
+ };
527
+ function createNotificationSettingsStorage() {
528
+ const storage = (0, import_connect_core10.createStorageAdapter)("local", "naculus_notif_");
529
+ return {
530
+ getItem: async (key) => {
531
+ try {
532
+ return await storage.get(key);
533
+ } catch (cause) {
534
+ console.warn(
535
+ "notification settings: failed to read from storage:",
536
+ cause
537
+ );
538
+ return null;
539
+ }
540
+ },
541
+ setItem: async (key, value) => {
542
+ try {
543
+ await storage.set(key, value);
544
+ } catch (cause) {
545
+ console.warn(
546
+ "notification settings: failed to write to storage:",
547
+ cause
548
+ );
549
+ }
550
+ },
551
+ removeItem: async (key) => {
552
+ try {
553
+ await storage.remove(key);
554
+ } catch (cause) {
555
+ console.warn(
556
+ "notification settings: failed to remove from storage:",
557
+ cause
558
+ );
559
+ }
560
+ }
561
+ };
562
+ }
563
+ async function loadNotificationSettings(storage) {
564
+ return storage.getItem(NOTIFICATION_SETTINGS_KEY);
565
+ }
566
+ function saveNotificationSettings(storage, settings) {
567
+ storage.setItem(NOTIFICATION_SETTINGS_KEY, settings).catch(() => {
568
+ });
569
+ }
570
+ function updateNotificationSettings(current, update) {
571
+ return { ...current, ...update };
572
+ }
573
+ function channelsUpdate(channels) {
574
+ const update = {};
575
+ if (channels.includes("telegram")) update.telegram = true;
576
+ if (channels.includes("webpush")) update.webpush = true;
577
+ if (channels.includes("inapp")) update.inapp = true;
578
+ return update;
579
+ }
580
+ function mutedChainSettings(settings, chainId, muted) {
581
+ return {
582
+ mutedChains: muted ? [.../* @__PURE__ */ new Set([...settings.mutedChains, chainId])] : settings.mutedChains.filter((id) => id !== chainId)
583
+ };
584
+ }
585
+ function createNotification(item) {
586
+ return {
587
+ ...item,
588
+ id: `notif_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
589
+ timestamp: Date.now()
590
+ };
591
+ }
592
+ function sendItem(channel, item) {
593
+ return channel.send({
594
+ id: item.id,
595
+ userId: "",
596
+ txHash: item.txHash,
597
+ chainId: "",
598
+ chainName: item.chainName,
599
+ status: item.status,
600
+ title: item.title,
601
+ body: item.body,
602
+ valueFormatted: item.valueFormatted,
603
+ explorerUrl: item.explorerUrl,
604
+ timestamp: item.timestamp
605
+ });
606
+ }
607
+ function addInAppNotification(channel, item) {
608
+ void sendItem(channel, createNotification(item));
609
+ }
610
+ async function clearOneInAppNotification(channel, id) {
611
+ const remaining = channel.getHistory().filter((item) => item.id !== id);
612
+ channel.clear();
613
+ await Promise.all(remaining.map((item) => sendItem(channel, item)));
614
+ return channel.getHistory();
615
+ }
616
+
617
+ // src/destination.ts
618
+ var import_connect_core11 = require("@naculus/connect-core");
619
+ var DEAD_ADDRESSES = /* @__PURE__ */ new Set([
620
+ "0x0000000000000000000000000000000000000001",
621
+ "0x000000000000000000000000000000000000dead"
622
+ ]);
623
+ function isBurnDestination(address) {
624
+ const lower = address.toLowerCase();
625
+ return DEAD_ADDRESSES.has(lower) || lower.includes("dead");
626
+ }
627
+ function validateDestination(address) {
628
+ if (!address) return { isValid: false, level: "blocked", issue: "empty" };
629
+ if (!(0, import_connect_core11.isEvmAddress)(address)) {
630
+ return { isValid: false, level: "blocked", issue: "invalid_format" };
631
+ }
632
+ if ((0, import_connect_core11.isZeroAddress)(address)) {
633
+ return { isValid: false, level: "blocked", issue: "zero_address" };
634
+ }
635
+ if (isBurnDestination(address)) {
636
+ return { isValid: false, level: "blocked", issue: "burn_address" };
637
+ }
638
+ return { isValid: true, level: "ok", issue: null };
639
+ }
640
+ function bareEvmAddress(account) {
641
+ if (!account) return null;
642
+ const value = account.includes(":") ? account.split(":").pop() : account;
643
+ return value && (0, import_connect_core11.isEvmAddress)(value) ? value : null;
644
+ }
645
+
646
+ // src/routing.ts
647
+ var import_connect_core12 = require("@naculus/connect-core");
648
+ function isPositiveIntegerAmount(amount) {
649
+ return /^(?:0|[1-9][0-9]*)$/.test(amount) && BigInt(amount) > 0n;
650
+ }
651
+ function isQuotableInput(input) {
652
+ return Boolean(
653
+ input.fromChain && input.toChain && input.fromToken && isPositiveIntegerAmount(input.amount)
654
+ );
655
+ }
656
+ function compareCostsKey(input) {
657
+ const options = input.options;
658
+ const optionsKey = options ? Object.keys(options).sort().map((key) => {
659
+ const value = options[key];
660
+ return `${key}=${typeof value === "object" && value !== null ? "[object]" : String(value)}`;
661
+ }).join("&") : "";
662
+ return `${input.operation}|${(input.chains ?? []).join(",")}|${optionsKey}`;
663
+ }
664
+ function validateRouteRecipient(quote, recipient) {
665
+ if (typeof recipient !== "string" || recipient.trim() === "") {
666
+ return {
667
+ code: "invalid_recipient",
668
+ message: "A recipient address is required"
669
+ };
670
+ }
671
+ const namespace = quote?.toChain?.split(":")[0];
672
+ if (namespace && !(0, import_connect_core12.isValidAddress)(recipient, namespace)) {
673
+ return {
674
+ code: "invalid_recipient",
675
+ message: `"${recipient}" is not a valid ${namespace} address for the destination chain ${quote?.toChain}`
676
+ };
677
+ }
678
+ return null;
679
+ }
680
+ function toExecuteRouteError(cause) {
681
+ const error = cause;
682
+ return {
683
+ code: error?.code ?? "execution_failed",
684
+ message: error?.message ?? String(cause),
685
+ details: error?.details
686
+ };
687
+ }
688
+
689
+ // src/session-key-manager.ts
690
+ var import_connect_core13 = require("@naculus/connect-core");
691
+ var sharedManager = null;
692
+ var sharedFingerprint = null;
693
+ function sessionKeyConfigFingerprint(config) {
694
+ if (!config) return "";
695
+ return JSON.stringify({
696
+ defaultMaxTotalValue: config.defaultMaxTotalValue?.toString(),
697
+ defaultMaxTxCount: config.defaultMaxTxCount,
698
+ defaultExpiryMs: config.defaultExpiryMs,
699
+ requireAllowedContracts: config.requireAllowedContracts,
700
+ forbiddenMethods: config.forbiddenMethods,
701
+ pbkdf2Iterations: config.pbkdf2Iterations,
702
+ unsafeAllowWeakKdf: config.unsafeAllowWeakKdf,
703
+ storagePrefix: config.storagePrefix,
704
+ encryptionKey: config.encryptionKey,
705
+ encryptionSalt: config.encryptionSalt
706
+ });
707
+ }
708
+ function getSharedSessionKeyManager(config) {
709
+ const fingerprint = sessionKeyConfigFingerprint(config);
710
+ if (!sharedManager) {
711
+ const storagePrefix = config?.storagePrefix ?? import_connect_core13.DEFAULT_SESSION_KEY_CONFIG.storagePrefix;
712
+ sharedManager = new import_connect_core13.SessionKeyManager(
713
+ config,
714
+ typeof window !== "undefined" ? new import_connect_core13.LocalStorageAdapter(`${storagePrefix}:`) : new import_connect_core13.MemoryStorageAdapter()
715
+ );
716
+ sharedFingerprint = fingerprint;
717
+ return sharedManager;
718
+ }
719
+ if (fingerprint !== "" && fingerprint !== sharedFingerprint) {
720
+ throw new import_connect_core13.WalletError(
721
+ "invalid_input",
722
+ "useSessionKeys is backed by a process-wide SessionKeyManager, and a different spending configuration was supplied after it was created. The second configuration would be ignored, so the caller would be operating under limits it did not set. Use one configuration per application, or construct a SessionKeyManager directly."
723
+ );
724
+ }
725
+ return sharedManager;
726
+ }
727
+ function resetSharedSessionKeyManager() {
728
+ sharedManager = null;
729
+ sharedFingerprint = null;
730
+ }
731
+
732
+ // src/user-op-receipt.ts
733
+ var InvalidUserOperationReceiptError = class extends Error {
734
+ constructor(message) {
735
+ super(message);
736
+ this.name = "InvalidUserOperationReceiptError";
737
+ }
738
+ };
739
+ function isRecord(value) {
740
+ return typeof value === "object" && value !== null && !Array.isArray(value);
741
+ }
742
+ function isAddress(value) {
743
+ return typeof value === "string" && /^0x[0-9a-fA-F]{40}$/.test(value);
744
+ }
745
+ function isHash(value) {
746
+ return typeof value === "string" && /^0x[0-9a-fA-F]{64}$/.test(value);
747
+ }
748
+ function isHexData(value) {
749
+ return typeof value === "string" && /^0x(?:[0-9a-fA-F]{2})*$/.test(value);
750
+ }
751
+ function parseQuantity(value, field) {
752
+ if (typeof value !== "string" || !/^(?:0x(?:0|[1-9a-fA-F][0-9a-fA-F]*)|(?:0|[1-9][0-9]*))$/.test(value)) {
753
+ throw new InvalidUserOperationReceiptError(
754
+ `Bundler returned an invalid ${field}.`
755
+ );
756
+ }
757
+ return BigInt(value);
758
+ }
759
+ function parseUserOperationReceipt(value, expectedHash) {
760
+ if (!isRecord(value)) {
761
+ throw new InvalidUserOperationReceiptError(
762
+ "Bundler returned an invalid UserOperation receipt."
763
+ );
764
+ }
765
+ if (!isHash(value.userOpHash) || value.userOpHash.toLowerCase() !== expectedHash.toLowerCase()) {
766
+ throw new InvalidUserOperationReceiptError(
767
+ "Bundler receipt does not match the requested UserOperation hash."
768
+ );
769
+ }
770
+ if (!isAddress(value.entryPoint) || !isAddress(value.sender)) {
771
+ throw new InvalidUserOperationReceiptError(
772
+ "Bundler receipt contains an invalid account address."
773
+ );
774
+ }
775
+ if (value.paymaster !== void 0 && value.paymaster !== null && !isAddress(value.paymaster)) {
776
+ throw new InvalidUserOperationReceiptError(
777
+ "Bundler receipt contains an invalid paymaster address."
778
+ );
779
+ }
780
+ if (typeof value.success !== "boolean" || !isHash(value.transactionHash)) {
781
+ throw new InvalidUserOperationReceiptError(
782
+ "Bundler receipt contains an invalid execution result."
783
+ );
784
+ }
785
+ if (!Array.isArray(value.logs)) {
786
+ throw new InvalidUserOperationReceiptError(
787
+ "Bundler receipt contains invalid logs."
788
+ );
789
+ }
790
+ const logs = value.logs.map((candidate) => {
791
+ if (!isRecord(candidate) || !isAddress(candidate.address) || !Array.isArray(candidate.topics) || !candidate.topics.every(isHash) || !isHexData(candidate.data)) {
792
+ throw new InvalidUserOperationReceiptError(
793
+ "Bundler receipt contains an invalid log entry."
794
+ );
795
+ }
796
+ return {
797
+ address: candidate.address,
798
+ topics: candidate.topics,
799
+ data: candidate.data
800
+ };
801
+ });
802
+ return {
803
+ userOpHash: value.userOpHash,
804
+ entryPoint: value.entryPoint,
805
+ sender: value.sender,
806
+ nonce: parseQuantity(value.nonce, "nonce"),
807
+ ...value.paymaster === void 0 || value.paymaster === null ? {} : { paymaster: value.paymaster },
808
+ actualGasUsed: parseQuantity(value.actualGasUsed, "actualGasUsed"),
809
+ actualGasCost: parseQuantity(value.actualGasCost, "actualGasCost"),
810
+ success: value.success,
811
+ transactionHash: value.transactionHash,
812
+ logs
813
+ };
814
+ }
815
+ async function fetchUserOperationReceipt(bundlerUrl, hash, signal) {
816
+ const response = await fetch(bundlerUrl, {
817
+ method: "POST",
818
+ headers: { "Content-Type": "application/json" },
819
+ body: JSON.stringify({
820
+ jsonrpc: "2.0",
821
+ id: 1,
822
+ method: "eth_getUserOperationReceipt",
823
+ params: [hash]
824
+ }),
825
+ signal
826
+ });
827
+ if (!response.ok) {
828
+ throw new Error(
829
+ `Bundler returned HTTP ${response.status} while reading UserOperation status.`
830
+ );
831
+ }
832
+ const json = await response.json();
833
+ if (json.error) {
834
+ throw new Error(
835
+ typeof json.error.message === "string" ? json.error.message : "Bundler returned a JSON-RPC error."
836
+ );
837
+ }
838
+ if (json.result === void 0 || json.result === null) return null;
839
+ return parseUserOperationReceipt(json.result, hash);
840
+ }
841
+
842
+ // src/smart-account.ts
843
+ var import_connect_core14 = require("@naculus/connect-core");
844
+ function resolveUserOpChain(optionsChainId, connectedChainId) {
845
+ const chainId = resolveEvmChainId(optionsChainId, connectedChainId);
846
+ if (!chainId) {
847
+ throw new import_connect_core14.WalletError(
848
+ "invalid_chain",
849
+ optionsChainId || connectedChainId ? `Invalid EVM chain ID: ${optionsChainId ?? connectedChainId}` : "No EVM chain to send on. Connect a wallet or pass options.chainId."
850
+ );
851
+ }
852
+ if (connectedChainId && connectedChainId !== chainId) {
853
+ throw new import_connect_core14.WalletError(
854
+ "chain_mismatch",
855
+ `Connected chain ${connectedChainId} does not match UserOperation chain ${chainId}.`
856
+ );
857
+ }
858
+ return chainId;
859
+ }
860
+ function buildSmartAccountConfig(owner, chainId, options = {}) {
861
+ return {
862
+ owner,
863
+ accountType: options.accountType ?? "simple",
864
+ entryPoint: options.entryPoint ?? import_connect_core14.AA_SUPPORTED_CHAINS[chainId]?.entryPoint ?? import_connect_core14.DEFAULT_ENTRY_POINT,
865
+ chainId,
866
+ salt: options.salt
867
+ };
868
+ }
869
+ function assertHexSignature(value) {
870
+ if (typeof value !== "string" || !/^0x(?:[0-9a-fA-F]{2})+$/.test(value)) {
871
+ throw new import_connect_core14.WalletError(
872
+ "signature_rejected",
873
+ "Wallet returned an invalid UserOperation signature."
874
+ );
875
+ }
876
+ return value;
877
+ }
878
+
879
+ // src/delegation-policy.ts
880
+ var import_connect_core15 = require("@naculus/connect-core");
881
+ function sorted(values) {
882
+ return values ? [...values].map((value) => value.toLowerCase()).sort() : null;
883
+ }
884
+ function sameExecutionIntent(requested, prepared) {
885
+ const sameHex = (left, right, empty) => {
886
+ const l = left === void 0 ? empty : left.toLowerCase();
887
+ const r = right === void 0 ? empty : right.toLowerCase();
888
+ return l === r;
889
+ };
890
+ const sameQuantity = (left, right) => {
891
+ try {
892
+ return BigInt(left ?? "0") === BigInt(right ?? "0");
893
+ } catch {
894
+ return false;
895
+ }
896
+ };
897
+ return sameHex(requested.to, prepared.to) && sameHex(requested.data, prepared.data, "0x") && sameQuantity(requested.value, prepared.value) && requested.chainId === prepared.chainId;
898
+ }
899
+ function buildDelegationPolicyMessage(policy, origin) {
900
+ const tokenAllowances = policy.scope.tokenAllowances ? Object.entries(policy.scope.tokenAllowances).map(
901
+ ([token, value]) => [token.toLowerCase(), value.toString()]
902
+ ).sort(([left], [right]) => left.localeCompare(right)) : null;
903
+ const payload = {
904
+ version: 1,
905
+ origin,
906
+ signer: policy.signerAddress.toLowerCase(),
907
+ sessionId: policy.id,
908
+ sessionPublicKey: policy.publicKey.toLowerCase(),
909
+ expiresAt: new Date(policy.expiresAt).toISOString(),
910
+ mode: policy.scope.mode,
911
+ limits: {
912
+ maxTotalGas: policy.scope.maxTotalGas?.toString() ?? null,
913
+ maxGasPerTx: policy.scope.maxGasPerTx?.toString() ?? null,
914
+ maxTotalValue: policy.scope.maxTotalValue?.toString() ?? null,
915
+ maxValuePerTx: policy.scope.maxValuePerTx?.toString() ?? null,
916
+ maxTxCount: policy.scope.maxTxCount ?? null
917
+ },
918
+ allowedContracts: sorted(policy.scope.allowedContracts),
919
+ allowedMethods: sorted(policy.scope.allowedMethods),
920
+ allowedChainIds: policy.scope.allowedChainIds ? [...policy.scope.allowedChainIds].sort((left, right) => left - right) : null,
921
+ tokenAllowances
922
+ };
923
+ return `Naculus Session Policy v1
924
+ ${JSON.stringify(payload)}`;
925
+ }
926
+ function isVerifiablePolicy(policy) {
927
+ return policy.status === "active" && Boolean(policy.authorized) && policy.scope.mode === "offchain";
928
+ }
929
+ function createDelegationPolicyFlow(deps) {
930
+ const { manager, origin } = deps;
931
+ const verifyStoredPolicy = async (policy) => {
932
+ if (!isVerifiablePolicy(policy)) return false;
933
+ return manager.verifyOffchainAuthorization(
934
+ policy.id,
935
+ buildDelegationPolicyMessage(policy, origin),
936
+ deps.verifySignature
937
+ );
938
+ };
939
+ const createPolicy = async (scope) => {
940
+ const signer = deps.signer();
941
+ if (!signer) {
942
+ throw new import_connect_core15.WalletError("wallet_unavailable", "No active EVM account");
943
+ }
944
+ if (scope.mode && scope.mode !== "offchain") {
945
+ throw new import_connect_core15.WalletError(
946
+ "method_not_allowed",
947
+ "This flow creates signed off-chain policies only. EIP-7702 and AA-module policies require a configured on-chain execution adapter."
948
+ );
949
+ }
950
+ if (!deps.encryptionKeyConfigured) {
951
+ throw new import_connect_core15.WalletError(
952
+ "method_not_allowed",
953
+ "Persistent delegation policies require a host-provided encryptionKey. The deterministic compatibility fallback is not a production key boundary."
954
+ );
955
+ }
956
+ if (!deps.storageAvailable()) {
957
+ throw new import_connect_core15.WalletError(
958
+ "storage_unavailable",
959
+ "Persistent delegation policy storage is unavailable in this browser"
960
+ );
961
+ }
962
+ let draft = null;
963
+ try {
964
+ draft = await manager.createSessionKey(
965
+ { ...scope, mode: "offchain" },
966
+ signer
967
+ );
968
+ const message = buildDelegationPolicyMessage(draft, origin);
969
+ const signature = await deps.signMessage(message);
970
+ if (!/^0x[0-9a-fA-F]{130}$/.test(signature)) {
971
+ throw new import_connect_core15.WalletError(
972
+ "invalid_input",
973
+ "Wallet did not return a valid 65-byte EVM policy signature"
974
+ );
975
+ }
976
+ const recovers = await deps.verifySignature({
977
+ message,
978
+ signature,
979
+ signerAddress: signer
980
+ });
981
+ if (!recovers) {
982
+ throw new import_connect_core15.WalletError(
983
+ "invalid_input",
984
+ "Policy signature does not recover to the connected EVM account"
985
+ );
986
+ }
987
+ await manager.setAuthorization(draft.id, {
988
+ signerAddress: signer,
989
+ type: "offchain",
990
+ rawSignature: signature,
991
+ message
992
+ });
993
+ const authorized = (await manager.listSessions()).find(
994
+ (policy) => policy.id === draft?.id
995
+ );
996
+ if (!authorized?.authorized) {
997
+ throw new import_connect_core15.WalletError(
998
+ "invalid_input",
999
+ "Policy authorization was not persisted"
1000
+ );
1001
+ }
1002
+ if (!await verifyStoredPolicy(authorized)) {
1003
+ throw new import_connect_core15.WalletError(
1004
+ "invalid_input",
1005
+ "Persisted policy signature did not verify against its stored scope and origin"
1006
+ );
1007
+ }
1008
+ await deps.refresh();
1009
+ return authorized;
1010
+ } catch (cause) {
1011
+ if (draft) {
1012
+ try {
1013
+ await manager.revokeSession(draft.id);
1014
+ } catch {
1015
+ }
1016
+ }
1017
+ throw cause instanceof Error ? cause : new Error("Policy creation failed");
1018
+ }
1019
+ };
1020
+ const revokePolicy = async (policyId) => {
1021
+ await manager.revokeSession(policyId);
1022
+ await deps.refresh();
1023
+ };
1024
+ const previewPolicyExecution = async (policyId, tx, callCount = 1, atomicity = "preferred") => {
1025
+ const policy = (await manager.listSessions()).find((item) => item.id === policyId) ?? null;
1026
+ const scope = await manager.checkSessionScope(policyId, tx);
1027
+ const plan = deps.previewExecution(callCount, atomicity);
1028
+ const signer = deps.signer();
1029
+ const authorizationVerified = policy ? await verifyStoredPolicy(policy) : false;
1030
+ const signerMatches = Boolean(
1031
+ policy && signer && policy.signerAddress.toLowerCase() === signer.toLowerCase()
1032
+ );
1033
+ const adapter = deps.adapter;
1034
+ let adapterCheck = null;
1035
+ if (policy && adapter && authorizationVerified && signerMatches && scope.valid) {
1036
+ try {
1037
+ adapterCheck = await adapter.check({ policy, transaction: tx });
1038
+ } catch (cause) {
1039
+ adapterCheck = {
1040
+ ready: false,
1041
+ authorizationInstalled: false,
1042
+ sponsored: false,
1043
+ promptless: false,
1044
+ reason: cause instanceof Error ? `Execution adapter check failed: ${cause.message}` : "Execution adapter check failed."
1045
+ };
1046
+ }
1047
+ }
1048
+ const delegation = deps.delegation();
1049
+ const delegationMatches = Boolean(
1050
+ adapter?.route !== "eip7702" || delegation.delegated === true && adapterCheck?.executorAddress && delegation.delegate?.toLowerCase() === adapterCheck.executorAddress.toLowerCase()
1051
+ );
1052
+ const policyReady = Boolean(
1053
+ policy?.status === "active" && policy.authorized && authorizationVerified && policy.scope.mode === "offchain" && signerMatches && scope.valid
1054
+ );
1055
+ const adapterSponsorshipReady = Boolean(
1056
+ deps.sponsorship !== "required" || adapterCheck?.sponsored
1057
+ );
1058
+ const broadcastReady = Boolean(
1059
+ policyReady && callCount === 1 && adapterCheck?.ready && adapterCheck.authorizationInstalled && adapterCheck.promptless && adapterSponsorshipReady && delegationMatches
1060
+ );
1061
+ const ready = Boolean(policyReady && (plan.route || broadcastReady));
1062
+ const reason = !policy ? "Policy not found." : policy.status !== "active" ? `Policy is ${policy.status}.` : !policy.authorized ? "The main wallet has not signed this policy." : !authorizationVerified ? "The persisted policy signature no longer matches its scope, signer, or origin." : !signerMatches ? "The connected account is not the policy signer." : !scope.valid ? scope.reason ?? "The transaction is outside the policy scope." : broadcastReady ? `The configured ${adapter?.route ?? "AA/7702"} adapter can submit this policy-authorized operation without another main-wallet prompt.${adapterCheck?.sponsored ? " Gas sponsorship is guaranteed." : ""} ${adapterCheck?.reason ?? "The on-chain execution adapter is ready."}` : !adapter ? `${plan.reason} The signed off-chain policy permits this request; an AA/7702 adapter is still required to broadcast without another wallet prompt.` : !adapterCheck?.ready || !adapterCheck.authorizationInstalled ? `${plan.reason} ${adapterCheck?.reason ?? "The execution adapter is not ready."}` : !adapterCheck.promptless ? `${plan.reason} The configured adapter would invoke the main wallet again, so promptless broadcast is not ready.` : !adapterSponsorshipReady ? `${plan.reason} Sponsored gas is required, but the configured adapter does not guarantee sponsorship.` : callCount !== 1 ? `${plan.reason} This policy adapter prepares one execution at a time and cannot claim a multi-call broadcast.` : !delegationMatches ? `${plan.reason} The configured EIP-7702 executor does not match the account's on-chain delegation.` : !plan.route ? plan.reason : `${plan.reason} ${adapterCheck.reason}`;
1063
+ return {
1064
+ policy,
1065
+ scope,
1066
+ execution: plan,
1067
+ signerMatches,
1068
+ authorizationVerified,
1069
+ ready,
1070
+ broadcastReady,
1071
+ broadcastRoute: broadcastReady ? adapter?.route ?? null : null,
1072
+ onchainAuthorizationVerified: Boolean(
1073
+ adapterCheck?.authorizationInstalled && delegationMatches
1074
+ ),
1075
+ broadcastSponsored: broadcastReady ? adapterCheck?.sponsored ?? false : null,
1076
+ broadcastPromptless: Boolean(broadcastReady && adapterCheck?.promptless),
1077
+ reason
1078
+ };
1079
+ };
1080
+ const signVerified = (policyId, digest, tx) => manager.signWithVerifiedOffchainAuthorization(
1081
+ policyId,
1082
+ (authoritativePolicy) => buildDelegationPolicyMessage(authoritativePolicy, origin),
1083
+ deps.verifySignature,
1084
+ digest,
1085
+ tx
1086
+ );
1087
+ const signPolicyDigest = async (policyId, digest, tx) => {
1088
+ const preview = await previewPolicyExecution(policyId, tx, 1, "any");
1089
+ if (!preview.ready) {
1090
+ throw new import_connect_core15.WalletError("method_not_allowed", preview.reason);
1091
+ }
1092
+ return signVerified(policyId, digest, tx);
1093
+ };
1094
+ const executePolicy = async (policyId, tx) => {
1095
+ const adapter = deps.adapter;
1096
+ if (!adapter) {
1097
+ throw new import_connect_core15.WalletError(
1098
+ "method_not_allowed",
1099
+ "No session-policy-aware AA/7702 execution adapter is configured."
1100
+ );
1101
+ }
1102
+ const preview = await previewPolicyExecution(policyId, tx, 1, "any");
1103
+ if (!preview.broadcastReady || !preview.policy) {
1104
+ throw new import_connect_core15.WalletError("method_not_allowed", preview.reason);
1105
+ }
1106
+ const prepared = await adapter.prepare({
1107
+ policy: preview.policy,
1108
+ transaction: tx
1109
+ });
1110
+ if (!/^0x[0-9a-fA-F]{64}$/.test(prepared.digest)) {
1111
+ throw new import_connect_core15.WalletError(
1112
+ "invalid_input",
1113
+ "Execution adapter returned a digest that is not 32 bytes."
1114
+ );
1115
+ }
1116
+ if (!sameExecutionIntent(tx, prepared.transaction)) {
1117
+ throw new import_connect_core15.WalletError(
1118
+ "invalid_input",
1119
+ "Execution adapter changed the requested target, value, data, or chain."
1120
+ );
1121
+ }
1122
+ const currentCheck = await adapter.check({
1123
+ policy: preview.policy,
1124
+ transaction: prepared.transaction
1125
+ });
1126
+ const delegation = deps.delegation();
1127
+ const currentDelegationMatches = adapter.route !== "eip7702" || delegation.delegated === true && currentCheck.executorAddress !== void 0 && delegation.delegate?.toLowerCase() === currentCheck.executorAddress.toLowerCase();
1128
+ if (!currentCheck.ready || !currentCheck.authorizationInstalled || !currentCheck.promptless || deps.sponsorship === "required" && !currentCheck.sponsored || !currentDelegationMatches) {
1129
+ throw new import_connect_core15.WalletError(
1130
+ "method_not_allowed",
1131
+ currentCheck.reason || "The on-chain policy authorization is not ready."
1132
+ );
1133
+ }
1134
+ const signature = await signVerified(
1135
+ policyId,
1136
+ prepared.digest,
1137
+ prepared.transaction
1138
+ );
1139
+ const submission = await adapter.broadcast({
1140
+ policy: preview.policy,
1141
+ prepared,
1142
+ signature
1143
+ });
1144
+ if (submission.route !== adapter.route || submission.status !== "submitted" || !/^0x[0-9a-fA-F]{64}$/.test(submission.hash)) {
1145
+ throw new import_connect_core15.WalletError(
1146
+ "invalid_input",
1147
+ "Execution adapter returned an invalid submission result."
1148
+ );
1149
+ }
1150
+ await deps.refresh();
1151
+ return submission;
1152
+ };
1153
+ return {
1154
+ verifyStoredPolicy,
1155
+ createPolicy,
1156
+ revokePolicy,
1157
+ previewPolicyExecution,
1158
+ signPolicyDigest,
1159
+ executePolicy
1160
+ };
1161
+ }
1162
+
280
1163
  // src/web3-store.ts
281
- var import_connect_core7 = require("@naculus/connect-core");
1164
+ var import_connect_core16 = require("@naculus/connect-core");
282
1165
  function withTimeout(promise, ms, label = "Operation") {
283
1166
  let timeoutId;
284
1167
  const timeout = new Promise((_, reject) => {
@@ -300,7 +1183,7 @@ async function withRetry(fn, options) {
300
1183
  lastError = error;
301
1184
  if (attempt < options.maxRetries) {
302
1185
  const delay = options.baseDelay * 2 ** attempt;
303
- import_connect_core7.logger.warn(
1186
+ import_connect_core16.logger.warn(
304
1187
  "appkit/core",
305
1188
  `Retry attempt ${attempt + 1}/${options.maxRetries} after ${delay}ms`
306
1189
  );
@@ -365,33 +1248,116 @@ function web3Reducer(state, action) {
365
1248
  return state;
366
1249
  }
367
1250
  }
1251
+
1252
+ // src/siwx-policy.ts
1253
+ function defaultSiwxDomain(location) {
1254
+ return location?.host ?? "localhost";
1255
+ }
1256
+ function defaultSiwxUri(location) {
1257
+ return location?.origin ?? "http://localhost";
1258
+ }
1259
+ function isSiwxExpired(result, now) {
1260
+ const value = result.message.expirationTime;
1261
+ if (!value) return false;
1262
+ const timestamp = new Date(value).getTime();
1263
+ return !Number.isFinite(timestamp) || timestamp <= now.getTime();
1264
+ }
1265
+ function isSiwxNotBeforeValid(result, now) {
1266
+ const value = result.message.notBefore;
1267
+ if (!value) return true;
1268
+ const timestamp = new Date(value).getTime();
1269
+ return Number.isFinite(timestamp) && timestamp <= now.getTime();
1270
+ }
1271
+ function randomSuffix() {
1272
+ const bytes = new Uint8Array(8);
1273
+ crypto.getRandomValues(bytes);
1274
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(
1275
+ ""
1276
+ );
1277
+ }
1278
+ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
1279
+ return {
1280
+ id: `siwx_${now.getTime().toString(36)}_${randomSuffix()}`,
1281
+ chainId: result.message.chainId,
1282
+ address: result.message.address,
1283
+ domain: result.message.domain,
1284
+ message: result.message,
1285
+ signature: result.signature,
1286
+ issuedAt: result.message.issuedAt ?? now.toISOString(),
1287
+ expiresAt: result.message.expirationTime ?? null,
1288
+ refreshedAt: null
1289
+ };
1290
+ }
368
1291
  // Annotate the CommonJS export names for ESM import in node:
369
1292
  0 && (module.exports = {
1293
+ DEFAULT_NOTIFICATION_SETTINGS,
1294
+ InvalidUserOperationReceiptError,
1295
+ NOTIFICATION_SETTINGS_KEY,
370
1296
  __resetResolverForTests,
1297
+ addInAppNotification,
1298
+ assertHexSignature,
371
1299
  atomicSupportFor,
1300
+ bareEvmAddress,
1301
+ buildDelegationPolicyMessage,
1302
+ buildSmartAccountConfig,
372
1303
  chainNamespace,
373
1304
  chainNumber,
374
1305
  chainsForNamespace,
1306
+ channelsUpdate,
1307
+ clearOneInAppNotification,
1308
+ compareCostsKey,
375
1309
  createDecimalsCache,
1310
+ createDelegationPolicyFlow,
1311
+ createNotification,
1312
+ createNotificationSettingsStorage,
376
1313
  decodeRevertReason,
1314
+ defaultSiwxDomain,
1315
+ defaultSiwxUri,
377
1316
  describeChain,
378
1317
  eip155ChainIdToNumber,
1318
+ encodeErc20Approve,
1319
+ encodeErc20Transfer,
1320
+ encodeErc20TransferFrom,
1321
+ fetchUserOperationReceipt,
379
1322
  getResolver,
1323
+ getSharedSessionKeyManager,
380
1324
  initialWeb3State,
1325
+ isBurnDestination,
381
1326
  isEvmChainId,
1327
+ isPositiveIntegerAmount,
1328
+ isQuotableInput,
1329
+ isSiwxExpired,
1330
+ isSiwxNotBeforeValid,
1331
+ isVerifiablePolicy,
1332
+ loadNotificationSettings,
1333
+ mutedChainSettings,
382
1334
  normalizeCapabilities,
383
1335
  normalizeEip155ChainId,
1336
+ parseUserOperationReceipt,
384
1337
  readDecimals,
385
1338
  readSolanaRoles,
1339
+ resetSharedSessionKeyManager,
386
1340
  resolveChain,
1341
+ resolveContextSimulationEndpoint,
387
1342
  resolveEvmChainId,
388
1343
  resolveRevertReason,
1344
+ resolveSimulationEndpoint,
1345
+ resolveUserOpChain,
1346
+ sameExecutionIntent,
1347
+ saveNotificationSettings,
389
1348
  selectChainCapabilities,
1349
+ sessionKeyConfigFingerprint,
1350
+ simulateTransactionPreview,
1351
+ siwxResultToSession,
390
1352
  toChainSwitchError,
391
1353
  toEip155Accounts,
1354
+ toExecuteRouteError,
392
1355
  toViemChain,
393
1356
  tokenChainMismatch,
394
1357
  tokenKey,
1358
+ updateNotificationSettings,
1359
+ validateDestination,
1360
+ validateRouteRecipient,
395
1361
  web3Reducer,
396
1362
  withRetry,
397
1363
  withTimeout,