@phantom/browser-sdk 1.0.0 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,11 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
- AddressType: () => import_client4.AddressType,
33
+ AddressType: () => import_client5.AddressType,
34
34
  BrowserSDK: () => BrowserSDK,
35
35
  DebugCategory: () => DebugCategory,
36
36
  DebugLevel: () => DebugLevel,
37
- NetworkId: () => import_constants5.NetworkId,
37
+ NetworkId: () => import_constants7.NetworkId,
38
+ PHANTOM_ICON: () => import_constants8.PHANTOM_ICON,
38
39
  debug: () => debug,
39
40
  detectBrowser: () => detectBrowser,
40
41
  getBrowserDisplayName: () => getBrowserDisplayName,
@@ -51,7 +52,7 @@ module.exports = __toCommonJS(src_exports);
51
52
  var import_client = require("@phantom/client");
52
53
 
53
54
  // src/providers/injected/index.ts
54
- var import_client3 = require("@phantom/client");
55
+ var import_client4 = require("@phantom/client");
55
56
 
56
57
  // src/debug.ts
57
58
  var DebugLevel = /* @__PURE__ */ ((DebugLevel2) => {
@@ -128,12 +129,27 @@ var DebugCategory = {
128
129
  };
129
130
 
130
131
  // src/wallets/discovery.ts
131
- var import_client2 = require("@phantom/client");
132
+ var import_constants = require("@phantom/constants");
133
+ var import_client3 = require("@phantom/client");
132
134
  var import_browser_injected_sdk = require("@phantom/browser-injected-sdk");
133
135
  var import_browser_injected_sdk2 = require("@phantom/browser-injected-sdk");
134
136
  var import_solana = require("@phantom/browser-injected-sdk/solana");
135
137
  var import_ethereum = require("@phantom/browser-injected-sdk/ethereum");
136
138
  var import_auto_confirm = require("@phantom/browser-injected-sdk/auto-confirm");
139
+
140
+ // src/wallets/custom-wallets.ts
141
+ var import_client2 = require("@phantom/client");
142
+ var CUSTOM_WALLET_CONFIGS = [
143
+ {
144
+ id: "coinbase-wallet",
145
+ name: "Coinbase Wallet",
146
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTI4IDU2YzE1LjQ2NCAwIDI4LTEyLjUzNiAyOC0yOFM0My40NjQgMCAyOCAwIDAgMTIuNTM2IDAgMjhzMTIuNTM2IDI4IDI4IDI4WiIgZmlsbD0iIzFCNTNFNCIvPjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNyAyOGMwIDExLjU5OCA5LjQwMiAyMSAyMSAyMXMyMS05LjQwMiAyMS0yMVMzOS41OTggNyAyOCA3IDcgMTYuNDAyIDcgMjhabTE3LjIzNC02Ljc2NmEzIDMgMCAwIDAtMyAzdjcuNTMzYTMgMyAwIDAgMCAzIDNoNy41MzNhMyAzIDAgMCAwIDMtM3YtNy41MzNhMyAzIDAgMCAwLTMtM2gtNy41MzNaIiBmaWxsPSIjZmZmIi8+PC9zdmc+",
147
+ windowProperty: "coinbaseSolana",
148
+ addressTypes: [import_client2.AddressType.solana]
149
+ }
150
+ ];
151
+
152
+ // src/wallets/discovery.ts
137
153
  function generateWalletIdFromEIP6963(info) {
138
154
  if (info.rdns) {
139
155
  return info.rdns.split(".").reverse().join("-");
@@ -166,7 +182,7 @@ function processEIP6963Providers(providers) {
166
182
  id: walletId,
167
183
  name: info.name,
168
184
  icon: info.icon,
169
- addressTypes: [import_client2.AddressType.ethereum],
185
+ addressTypes: [import_client3.AddressType.ethereum],
170
186
  providers: {
171
187
  // EIP-6963 provider implements EIP-1193 interface (IEthereumChain)
172
188
  ethereum: provider
@@ -346,7 +362,7 @@ async function discoverSolanaWallets() {
346
362
  return chainLower.startsWith("solana:") || chainLower === "solana";
347
363
  }) || wallet.features && typeof wallet.features === "object" && Object.keys(wallet.features).some((featureKey) => {
348
364
  const featureLower = featureKey.toLowerCase();
349
- return featureLower.includes("solana") || featureLower.includes("standard:connect") || featureLower.includes("standard:signTransaction");
365
+ return featureLower.startsWith("solana:");
350
366
  });
351
367
  if (!supportsSolana) {
352
368
  const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
@@ -376,7 +392,7 @@ async function discoverSolanaWallets() {
376
392
  id: walletId,
377
393
  name: wallet.name,
378
394
  icon: wallet.icon,
379
- addressTypes: [import_client2.AddressType.solana],
395
+ addressTypes: [import_client3.AddressType.solana],
380
396
  providers: {
381
397
  // Cast to ISolanaChain - Wallet Standard wallets have compatible methods
382
398
  // The InjectedWalletSolanaChain wrapper will handle the actual method calls
@@ -397,6 +413,51 @@ async function discoverSolanaWallets() {
397
413
  walletNames: wallets.map((w) => w.name)
398
414
  };
399
415
  debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard Solana discovery completed", finalLogData);
416
+ const customWallets = discoverCustomSolanaWallets();
417
+ wallets.push(...customWallets);
418
+ return wallets;
419
+ }
420
+ function discoverCustomSolanaWallets() {
421
+ const wallets = [];
422
+ if (typeof window === "undefined") {
423
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet discovery skipped (not in browser environment)");
424
+ return wallets;
425
+ }
426
+ debug.log(DebugCategory.BROWSER_SDK, "Starting custom Solana wallet discovery", {
427
+ configCount: CUSTOM_WALLET_CONFIGS.length
428
+ });
429
+ for (const config of CUSTOM_WALLET_CONFIGS) {
430
+ if (!config.addressTypes.includes(import_client3.AddressType.solana)) {
431
+ continue;
432
+ }
433
+ const provider = window[config.windowProperty];
434
+ if (!provider) {
435
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet not found", {
436
+ walletId: config.id,
437
+ windowProperty: config.windowProperty
438
+ });
439
+ continue;
440
+ }
441
+ debug.log(DebugCategory.BROWSER_SDK, "Discovered custom Solana wallet", {
442
+ walletId: config.id,
443
+ walletName: config.name,
444
+ windowProperty: config.windowProperty
445
+ });
446
+ wallets.push({
447
+ id: config.id,
448
+ name: config.name,
449
+ icon: config.icon,
450
+ addressTypes: config.addressTypes,
451
+ providers: {
452
+ solana: provider
453
+ },
454
+ discovery: "custom"
455
+ });
456
+ }
457
+ debug.log(DebugCategory.BROWSER_SDK, "Custom Solana wallet discovery completed", {
458
+ discoveredCount: wallets.length,
459
+ walletIds: wallets.map((w) => w.id)
460
+ });
400
461
  return wallets;
401
462
  }
402
463
  function discoverPhantomWallet(addressTypes) {
@@ -407,10 +468,10 @@ function discoverPhantomWallet(addressTypes) {
407
468
  return null;
408
469
  }
409
470
  const plugins = [(0, import_browser_injected_sdk2.createExtensionPlugin)()];
410
- if (addressTypes.includes(import_client2.AddressType.solana)) {
471
+ if (addressTypes.includes(import_client3.AddressType.solana)) {
411
472
  plugins.push((0, import_solana.createSolanaPlugin)());
412
473
  }
413
- if (addressTypes.includes(import_client2.AddressType.ethereum)) {
474
+ if (addressTypes.includes(import_client3.AddressType.ethereum)) {
414
475
  plugins.push((0, import_ethereum.createEthereumPlugin)());
415
476
  }
416
477
  plugins.push((0, import_auto_confirm.createAutoConfirmPlugin)());
@@ -418,12 +479,11 @@ function discoverPhantomWallet(addressTypes) {
418
479
  return {
419
480
  id: "phantom",
420
481
  name: "Phantom",
421
- icon: void 0,
422
- // Icon will be rendered from icons package in UI components
482
+ icon: import_constants.PHANTOM_ICON,
423
483
  addressTypes,
424
484
  providers: {
425
- solana: addressTypes.includes(import_client2.AddressType.solana) ? phantomInstance.solana : void 0,
426
- ethereum: addressTypes.includes(import_client2.AddressType.ethereum) ? phantomInstance.ethereum : void 0
485
+ solana: addressTypes.includes(import_client3.AddressType.solana) ? phantomInstance.solana : void 0,
486
+ ethereum: addressTypes.includes(import_client3.AddressType.ethereum) ? phantomInstance.ethereum : void 0
427
487
  },
428
488
  isPhantom: true,
429
489
  phantomInstance,
@@ -488,67 +548,65 @@ async function discoverWallets(addressTypes) {
488
548
  return Array.from(walletMap.values());
489
549
  }
490
550
 
551
+ // src/wallets/registry.ts
552
+ var import_constants2 = require("@phantom/constants");
553
+
491
554
  // src/providers/injected/chains/InjectedWalletSolanaChain.ts
492
555
  var import_eventemitter3 = require("eventemitter3");
493
556
  var import_buffer = require("buffer");
494
557
  var InjectedWalletSolanaChain = class {
495
558
  constructor(provider, walletId, walletName) {
559
+ // Expose eventEmitter for testing - allows tests to trigger events directly
496
560
  this.eventEmitter = new import_eventemitter3.EventEmitter();
497
- this._connected = false;
498
561
  this._publicKey = null;
499
562
  this.provider = provider;
500
563
  this.walletId = walletId;
501
564
  this.walletName = walletName;
502
565
  this.setupEventListeners();
503
566
  }
504
- get connected() {
505
- return this._connected;
506
- }
507
567
  get publicKey() {
508
568
  return this._publicKey;
509
569
  }
570
+ get isConnected() {
571
+ return this.provider.isConnected || !!this._publicKey;
572
+ }
510
573
  async connect(options) {
511
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect", {
512
- walletId: this.walletId,
513
- walletName: this.walletName,
514
- onlyIfTrusted: options?.onlyIfTrusted
515
- });
516
574
  try {
517
- const result = await this.provider.connect(options);
518
- if (typeof result === "string") {
519
- this._connected = true;
520
- this._publicKey = result;
521
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
575
+ await this.provider.connect(options);
576
+ const isConnected = this.provider.isConnected;
577
+ if (!isConnected || this.provider.publicKey === null) {
578
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Provider not connected after connect() call", {
522
579
  walletId: this.walletId,
523
580
  walletName: this.walletName,
524
- publicKey: result
581
+ providerConnected: isConnected,
582
+ providerPublicKey: this.provider.publicKey
525
583
  });
526
- return { publicKey: result };
527
- }
528
- if (typeof result === "object" && result !== null && "publicKey" in result) {
529
- this._connected = true;
530
- this._publicKey = result.publicKey;
531
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
584
+ throw new Error("Provider not connected after connect() call");
585
+ }
586
+ let publicKey;
587
+ const providerPublicKey = this.provider.publicKey;
588
+ if (typeof providerPublicKey === "string") {
589
+ publicKey = providerPublicKey;
590
+ } else if (providerPublicKey !== null && providerPublicKey !== void 0 && typeof providerPublicKey.toString === "function") {
591
+ publicKey = providerPublicKey.toString();
592
+ } else {
593
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Invalid publicKey format in provider state", {
532
594
  walletId: this.walletId,
533
595
  walletName: this.walletName,
534
- publicKey: result.publicKey
596
+ publicKeyType: typeof providerPublicKey
535
597
  });
536
- return result;
537
- }
538
- if (Array.isArray(result) && result.length > 0) {
539
- const firstAccount = result[0];
540
- if (typeof firstAccount === "object" && firstAccount !== null && "address" in firstAccount) {
541
- this._connected = true;
542
- this._publicKey = firstAccount.address;
543
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
544
- walletId: this.walletId,
545
- walletName: this.walletName,
546
- publicKey: firstAccount.address
547
- });
548
- return { publicKey: firstAccount.address };
549
- }
598
+ throw new Error("Invalid publicKey format in provider state");
550
599
  }
551
- throw new Error("Unexpected connect result format");
600
+ if (!publicKey || publicKey.length === 0) {
601
+ throw new Error("Empty publicKey from provider");
602
+ }
603
+ this._publicKey = publicKey;
604
+ debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
605
+ walletId: this.walletId,
606
+ walletName: this.walletName,
607
+ publicKey
608
+ });
609
+ return { publicKey };
552
610
  } catch (error) {
553
611
  debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect failed", {
554
612
  walletId: this.walletId,
@@ -565,7 +623,6 @@ var InjectedWalletSolanaChain = class {
565
623
  });
566
624
  try {
567
625
  await this.provider.disconnect();
568
- this._connected = false;
569
626
  this._publicKey = null;
570
627
  debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnected", {
571
628
  walletId: this.walletId,
@@ -701,27 +758,19 @@ var InjectedWalletSolanaChain = class {
701
758
  switchNetwork(_network) {
702
759
  return Promise.resolve();
703
760
  }
704
- getPublicKey() {
705
- return Promise.resolve(this._publicKey);
706
- }
707
- isConnected() {
708
- return this._connected;
709
- }
710
761
  setupEventListeners() {
711
762
  if (typeof this.provider.on === "function") {
712
763
  this.provider.on("connect", (publicKey) => {
713
- this._connected = true;
714
764
  this._publicKey = publicKey;
715
765
  this.eventEmitter.emit("connect", publicKey);
716
766
  });
717
767
  this.provider.on("disconnect", () => {
718
- this._connected = false;
719
768
  this._publicKey = null;
720
769
  this.eventEmitter.emit("disconnect");
721
770
  });
722
771
  this.provider.on("accountChanged", (publicKey) => {
723
- this._publicKey = publicKey;
724
- this.eventEmitter.emit("accountChanged", publicKey);
772
+ this._publicKey = publicKey ? publicKey : null;
773
+ this.eventEmitter.emit("accountChanged", this._publicKey);
725
774
  });
726
775
  }
727
776
  }
@@ -734,26 +783,29 @@ var InjectedWalletSolanaChain = class {
734
783
  };
735
784
 
736
785
  // src/providers/injected/chains/WalletStandardSolanaAdapter.ts
786
+ var import_eventemitter32 = require("eventemitter3");
737
787
  var import_parsers = require("@phantom/parsers");
788
+ var import_buffer2 = require("buffer");
738
789
  var import_bs58 = __toESM(require("bs58"));
739
790
  var WalletStandardSolanaAdapter = class {
740
791
  constructor(wallet, walletId, walletName) {
741
- this._connected = false;
792
+ this.eventEmitter = new import_eventemitter32.EventEmitter();
742
793
  this._publicKey = null;
743
794
  this.wallet = wallet;
744
795
  this.walletId = walletId;
745
796
  this.walletName = walletName;
746
- }
747
- get connected() {
748
- return this._connected;
797
+ this.setupEventListeners();
749
798
  }
750
799
  get publicKey() {
751
800
  return this._publicKey;
752
801
  }
802
+ get isConnected() {
803
+ return this._publicKey !== null;
804
+ }
753
805
  async connect(_options) {
754
806
  try {
755
- const connectFeature = this.wallet.features?.["standard:connect"];
756
- if (!connectFeature || typeof connectFeature.connect !== "function") {
807
+ const connectFeature = this.wallet.features["standard:connect"];
808
+ if (!connectFeature) {
757
809
  throw new Error("Wallet Standard connect feature not available");
758
810
  }
759
811
  const connectResult = await connectFeature.connect();
@@ -774,14 +826,13 @@ var WalletStandardSolanaAdapter = class {
774
826
  if (typeof firstAccount === "string") {
775
827
  address = firstAccount;
776
828
  } else if (typeof firstAccount === "object" && firstAccount !== null) {
777
- address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? Buffer.from(firstAccount.publicKey).toString("hex") : void 0);
829
+ address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? import_buffer2.Buffer.from(firstAccount.publicKey).toString("hex") : void 0);
778
830
  }
779
831
  if (!address) {
780
832
  throw new Error(
781
833
  `Could not extract address from account. Account structure: ${JSON.stringify(firstAccount, null, 2)}`
782
834
  );
783
835
  }
784
- this._connected = true;
785
836
  this._publicKey = address;
786
837
  return { publicKey: address };
787
838
  } catch (error) {
@@ -795,11 +846,10 @@ var WalletStandardSolanaAdapter = class {
795
846
  }
796
847
  async disconnect() {
797
848
  try {
798
- const disconnectFeature = this.wallet.features?.["standard:disconnect"];
799
- if (disconnectFeature && typeof disconnectFeature.disconnect === "function") {
849
+ const disconnectFeature = this.wallet.features["standard:disconnect"];
850
+ if (disconnectFeature) {
800
851
  await disconnectFeature.disconnect();
801
852
  }
802
- this._connected = false;
803
853
  this._publicKey = null;
804
854
  } catch (error) {
805
855
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana disconnect failed", {
@@ -812,14 +862,14 @@ var WalletStandardSolanaAdapter = class {
812
862
  }
813
863
  async signMessage(message) {
814
864
  try {
815
- const signMessageFeature = this.wallet.features?.["solana:signMessage"];
816
- if (!signMessageFeature || typeof signMessageFeature.signMessage !== "function") {
865
+ const signMessageFeature = this.wallet.features["solana:signMessage"];
866
+ if (!signMessageFeature) {
817
867
  throw new Error("Wallet Standard signMessage feature not available");
818
868
  }
819
869
  const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
820
870
  const result = await signMessageFeature.signMessage({
821
871
  message: messageBytes,
822
- account: this.wallet.accounts?.[0]
872
+ account: this.wallet.accounts[0]
823
873
  });
824
874
  if (!Array.isArray(result) || result.length === 0) {
825
875
  throw new Error(`Expected array result from signMessage, got: ${typeof result}`);
@@ -832,7 +882,7 @@ var WalletStandardSolanaAdapter = class {
832
882
  if (signature.length === 0) {
833
883
  throw new Error(`Signature is empty`);
834
884
  }
835
- const publicKey = signedMessageResult.account?.address || this.wallet.accounts?.[0]?.address || this._publicKey || "";
885
+ const publicKey = signedMessageResult.account?.address || this.wallet.accounts[0]?.address || this._publicKey || "";
836
886
  return { signature, publicKey };
837
887
  } catch (error) {
838
888
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signMessage failed", {
@@ -845,8 +895,8 @@ var WalletStandardSolanaAdapter = class {
845
895
  }
846
896
  async signTransaction(transaction) {
847
897
  try {
848
- const signTransactionFeature = this.wallet.features?.["solana:signTransaction"];
849
- if (!signTransactionFeature || typeof signTransactionFeature.signTransaction !== "function") {
898
+ const signTransactionFeature = this.wallet.features["solana:signTransaction"];
899
+ if (!signTransactionFeature) {
850
900
  throw new Error("Wallet Standard signTransaction feature not available");
851
901
  }
852
902
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -865,7 +915,8 @@ var WalletStandardSolanaAdapter = class {
865
915
  transactionData = firstItem.signedTransaction || firstItem.transaction;
866
916
  }
867
917
  } else if (results && typeof results === "object" && !Array.isArray(results)) {
868
- transactionData = results.transaction || results.signedTransaction;
918
+ const resultObj = results;
919
+ transactionData = resultObj.transaction || resultObj.signedTransaction;
869
920
  }
870
921
  if (!transactionData) {
871
922
  throw new Error("No transaction data found in Wallet Standard result");
@@ -887,8 +938,8 @@ var WalletStandardSolanaAdapter = class {
887
938
  }
888
939
  async signAndSendTransaction(transaction) {
889
940
  try {
890
- const signAndSendTransactionFeature = this.wallet.features?.["solana:signAndSendTransaction"];
891
- if (!signAndSendTransactionFeature || typeof signAndSendTransactionFeature.signAndSendTransaction !== "function") {
941
+ const signAndSendTransactionFeature = this.wallet.features["solana:signAndSendTransaction"];
942
+ if (!signAndSendTransactionFeature) {
892
943
  throw new Error("Wallet Standard signAndSendTransaction feature not available");
893
944
  }
894
945
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -959,40 +1010,87 @@ var WalletStandardSolanaAdapter = class {
959
1010
  throw error;
960
1011
  }
961
1012
  }
962
- async switchNetwork(network) {
963
- try {
964
- const switchNetworkFeature = this.wallet.features?.["standard:switchNetwork"];
965
- if (switchNetworkFeature && typeof switchNetworkFeature.switchNetwork === "function") {
966
- const chainId = network === "mainnet" ? "solana:mainnet" : "solana:devnet";
967
- await switchNetworkFeature.switchNetwork({ chain: chainId });
968
- }
969
- } catch (error) {
970
- debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana switchNetwork failed", {
1013
+ async switchNetwork(_network) {
1014
+ return Promise.resolve();
1015
+ }
1016
+ /**
1017
+ * Set up event listeners for Wallet Standard events
1018
+ * Maps Wallet Standard "change" events to "accountChanged" events
1019
+ *
1020
+ * Note: Wallet Standard only has a "change" event. There are no "connect" or "disconnect" events.
1021
+ * Connection/disconnection is indicated by the presence or absence of accounts in the change event.
1022
+ */
1023
+ setupEventListeners() {
1024
+ const eventsFeature = this.wallet.features["standard:events"];
1025
+ if (!eventsFeature) {
1026
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard events feature not available", {
971
1027
  walletId: this.walletId,
972
- walletName: this.walletName,
973
- network,
974
- error: error instanceof Error ? error.message : String(error)
1028
+ walletName: this.walletName
975
1029
  });
976
- throw error;
1030
+ return;
977
1031
  }
1032
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Wallet Standard event listeners", {
1033
+ walletId: this.walletId,
1034
+ walletName: this.walletName
1035
+ });
1036
+ eventsFeature.on("change", (properties) => {
1037
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard change event received", {
1038
+ walletId: this.walletId,
1039
+ walletName: this.walletName,
1040
+ hasAccounts: !!properties.accounts,
1041
+ accountCount: properties.accounts?.length || 0
1042
+ });
1043
+ if (properties.accounts !== void 0) {
1044
+ if (properties.accounts.length > 0) {
1045
+ const firstAccount = properties.accounts[0];
1046
+ const address = this.extractAccountAddress(firstAccount);
1047
+ if (address) {
1048
+ this._publicKey = address;
1049
+ this.eventEmitter.emit("accountChanged", address);
1050
+ this.eventEmitter.emit("connect", address);
1051
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and connect events", {
1052
+ walletId: this.walletId,
1053
+ walletName: this.walletName,
1054
+ address
1055
+ });
1056
+ } else {
1057
+ this._publicKey = null;
1058
+ this.eventEmitter.emit("accountChanged", null);
1059
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged event (null - invalid account)", {
1060
+ walletId: this.walletId,
1061
+ walletName: this.walletName
1062
+ });
1063
+ }
1064
+ } else {
1065
+ this._publicKey = null;
1066
+ this.eventEmitter.emit("accountChanged", null);
1067
+ this.eventEmitter.emit("disconnect");
1068
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and disconnect events", {
1069
+ walletId: this.walletId,
1070
+ walletName: this.walletName
1071
+ });
1072
+ }
1073
+ }
1074
+ });
978
1075
  }
979
- getPublicKey() {
980
- return Promise.resolve(this._publicKey);
981
- }
982
- isConnected() {
983
- return this._connected;
1076
+ extractAccountAddress(account) {
1077
+ return account.address;
984
1078
  }
985
- on(_event, _listener) {
986
- const eventsFeature = this.wallet.features?.["standard:events"];
987
- if (eventsFeature && typeof eventsFeature.on === "function") {
988
- eventsFeature.on(_event, _listener);
989
- }
1079
+ on(event, listener) {
1080
+ this.eventEmitter.on(event, listener);
1081
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Added event listener", {
1082
+ walletId: this.walletId,
1083
+ walletName: this.walletName,
1084
+ event
1085
+ });
990
1086
  }
991
- off(_event, _listener) {
992
- const eventsFeature = this.wallet.features?.["standard:events"];
993
- if (eventsFeature && typeof eventsFeature.off === "function") {
994
- eventsFeature.off(_event, _listener);
995
- }
1087
+ off(event, listener) {
1088
+ this.eventEmitter.off(event, listener);
1089
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Removed event listener", {
1090
+ walletId: this.walletId,
1091
+ walletName: this.walletName,
1092
+ event
1093
+ });
996
1094
  }
997
1095
  /**
998
1096
  * Serialize a transaction to Uint8Array for Wallet Standard API
@@ -1036,10 +1134,11 @@ var WalletStandardSolanaAdapter = class {
1036
1134
  };
1037
1135
 
1038
1136
  // src/providers/injected/chains/InjectedWalletEthereumChain.ts
1039
- var import_eventemitter32 = require("eventemitter3");
1137
+ var import_eventemitter33 = require("eventemitter3");
1040
1138
  var InjectedWalletEthereumChain = class {
1041
1139
  constructor(provider, walletId, walletName) {
1042
- this.eventEmitter = new import_eventemitter32.EventEmitter();
1140
+ // Expose eventEmitter for testing - allows tests to trigger events directly
1141
+ this.eventEmitter = new import_eventemitter33.EventEmitter();
1043
1142
  this._connected = false;
1044
1143
  this._chainId = "0x1";
1045
1144
  this._accounts = [];
@@ -1048,9 +1147,6 @@ var InjectedWalletEthereumChain = class {
1048
1147
  this.walletName = walletName;
1049
1148
  this.setupEventListeners();
1050
1149
  }
1051
- get connected() {
1052
- return this._connected;
1053
- }
1054
1150
  get chainId() {
1055
1151
  return this._chainId;
1056
1152
  }
@@ -1180,7 +1276,8 @@ var InjectedWalletEthereumChain = class {
1180
1276
  address
1181
1277
  });
1182
1278
  try {
1183
- const providerConnected = this.provider.isConnected?.() || this.provider.connected || false;
1279
+ const providerAny = this.provider;
1280
+ const providerConnected = (typeof providerAny.isConnected === "function" ? providerAny.isConnected() : false) || (typeof providerAny.connected === "boolean" ? providerAny.connected : false);
1184
1281
  if (!this._connected || this._accounts.length === 0 || !providerConnected) {
1185
1282
  debug.log(DebugCategory.INJECTED_PROVIDER, "Not connected, attempting to connect before signing", {
1186
1283
  walletId: this.walletId,
@@ -1413,6 +1510,7 @@ var InjectedWalletEthereumChain = class {
1413
1510
  });
1414
1511
  this.provider.on("accountsChanged", (accounts) => {
1415
1512
  this._accounts = accounts;
1513
+ this._connected = accounts.length > 0;
1416
1514
  this.eventEmitter.emit("accountsChanged", accounts);
1417
1515
  });
1418
1516
  this.provider.on("chainChanged", (chainId) => {
@@ -1429,218 +1527,13 @@ var InjectedWalletEthereumChain = class {
1429
1527
  }
1430
1528
  };
1431
1529
 
1432
- // src/providers/injected/chains/SolanaChain.ts
1433
- var import_eventemitter33 = require("eventemitter3");
1434
- var import_buffer2 = require("buffer");
1435
- var PhantomSolanaChain = class {
1436
- constructor(phantom) {
1437
- this._publicKey = null;
1438
- this.eventEmitter = new import_eventemitter33.EventEmitter();
1439
- this.phantom = phantom;
1440
- this.setupEventListeners();
1441
- }
1442
- // Wallet adapter compliant properties
1443
- get connected() {
1444
- return this._publicKey !== null;
1445
- }
1446
- get publicKey() {
1447
- return this._publicKey;
1448
- }
1449
- // Connection methods
1450
- async connect(options) {
1451
- const result = await this.phantom.solana.connect(options);
1452
- if (!result) {
1453
- throw new Error("Failed to connect to Solana wallet");
1454
- }
1455
- const publicKey = typeof result === "string" ? result : "";
1456
- this._publicKey = publicKey;
1457
- return { publicKey };
1458
- }
1459
- async disconnect() {
1460
- await this.phantom.solana.disconnect();
1461
- this._publicKey = null;
1462
- }
1463
- // Standard wallet adapter methods
1464
- async signMessage(message) {
1465
- const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
1466
- const result = await this.phantom.solana.signMessage(messageBytes);
1467
- return {
1468
- signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(import_buffer2.Buffer.from(result.signature, "base64")),
1469
- publicKey: this._publicKey || ""
1470
- };
1471
- }
1472
- async signTransaction(transaction) {
1473
- if (!this.connected) {
1474
- return Promise.reject(new Error("Provider not connected. Call provider connect first."));
1475
- }
1476
- try {
1477
- const result = await this.phantom.solana.signTransaction(transaction);
1478
- return result;
1479
- } catch (error) {
1480
- return Promise.reject(error);
1481
- }
1482
- }
1483
- async signAndSendTransaction(transaction) {
1484
- const result = await this.phantom.solana.signAndSendTransaction(transaction);
1485
- return { signature: result.signature };
1486
- }
1487
- async signAllTransactions(transactions) {
1488
- if (!this.connected) {
1489
- return Promise.reject(new Error("Provider not connected. Call provider connect first."));
1490
- }
1491
- try {
1492
- const result = await this.phantom.solana.signAllTransactions(transactions);
1493
- return result;
1494
- } catch (error) {
1495
- return Promise.reject(error);
1496
- }
1497
- }
1498
- async signAndSendAllTransactions(transactions) {
1499
- if (!this.connected) {
1500
- return Promise.reject(new Error("Provider not connected. Call provider connect first."));
1501
- }
1502
- try {
1503
- const result = await this.phantom.solana.signAndSendAllTransactions(transactions);
1504
- return { signatures: result.signatures };
1505
- } catch (error) {
1506
- return Promise.reject(error);
1507
- }
1508
- }
1509
- switchNetwork(_network) {
1510
- return Promise.resolve();
1511
- }
1512
- // Legacy methods
1513
- getPublicKey() {
1514
- return Promise.resolve(this._publicKey);
1515
- }
1516
- isConnected() {
1517
- return this.connected;
1518
- }
1519
- setupEventListeners() {
1520
- this.phantom.solana.addEventListener("connect", (publicKey) => {
1521
- this._publicKey = publicKey;
1522
- this.eventEmitter.emit("connect", publicKey);
1523
- });
1524
- this.phantom.solana.addEventListener("disconnect", () => {
1525
- this._publicKey = null;
1526
- this.eventEmitter.emit("disconnect");
1527
- });
1528
- this.phantom.solana.addEventListener("accountChanged", (publicKey) => {
1529
- this._publicKey = publicKey;
1530
- this.eventEmitter.emit("accountChanged", publicKey);
1531
- });
1532
- }
1533
- // Event methods for interface compliance
1534
- on(event, listener) {
1535
- this.eventEmitter.on(event, listener);
1536
- }
1537
- off(event, listener) {
1538
- this.eventEmitter.off(event, listener);
1539
- }
1540
- };
1541
-
1542
- // src/providers/injected/chains/EthereumChain.ts
1543
- var import_eventemitter34 = require("eventemitter3");
1544
- var PhantomEthereumChain = class {
1545
- constructor(phantom) {
1546
- this._chainId = "0x1";
1547
- this._accounts = [];
1548
- this.eventEmitter = new import_eventemitter34.EventEmitter();
1549
- this.phantom = phantom;
1550
- this.setupEventListeners();
1551
- }
1552
- // EIP-1193 compliant properties
1553
- get connected() {
1554
- return this._accounts.length > 0;
1555
- }
1556
- get chainId() {
1557
- return this._chainId;
1558
- }
1559
- get accounts() {
1560
- return this._accounts;
1561
- }
1562
- // EIP-1193 core method with eth_signTransaction support
1563
- async request(args) {
1564
- if (args.method === "eth_signTransaction") {
1565
- const [transaction] = args.params;
1566
- const result = await this.signTransaction(transaction);
1567
- return result;
1568
- }
1569
- const phantomProvider = await this.phantom.ethereum.getProvider();
1570
- return await phantomProvider.request(args);
1571
- }
1572
- // Connection methods
1573
- async connect() {
1574
- const accounts = await this.phantom.ethereum.getAccounts();
1575
- this._accounts = accounts;
1576
- return accounts;
1577
- }
1578
- async disconnect() {
1579
- await this.phantom.ethereum.disconnect();
1580
- this._accounts = [];
1581
- }
1582
- // Standard compliant methods (return raw values, not wrapped objects)
1583
- async signPersonalMessage(message, address) {
1584
- return await this.phantom.ethereum.signPersonalMessage(message, address);
1585
- }
1586
- async signTypedData(typedData, address) {
1587
- return await this.phantom.ethereum.signTypedData(typedData, address);
1588
- }
1589
- async signTransaction(transaction) {
1590
- return await this.phantom.ethereum.signTransaction(transaction);
1591
- }
1592
- async sendTransaction(transaction) {
1593
- return await this.phantom.ethereum.sendTransaction(transaction);
1594
- }
1595
- async switchChain(chainId) {
1596
- const hexChainId = typeof chainId === "string" ? chainId.toLowerCase().startsWith("0x") ? chainId : `0x${parseInt(chainId, 10).toString(16)}` : `0x${chainId.toString(16)}`;
1597
- await this.phantom.ethereum.switchChain(hexChainId);
1598
- this._chainId = hexChainId;
1599
- this.eventEmitter.emit("chainChanged", this._chainId);
1600
- }
1601
- async getChainId() {
1602
- const chainId = await this.phantom.ethereum.getChainId();
1603
- return parseInt(chainId, 16);
1604
- }
1605
- async getAccounts() {
1606
- return await this.phantom.ethereum.getAccounts();
1607
- }
1608
- isConnected() {
1609
- return this.connected;
1610
- }
1611
- setupEventListeners() {
1612
- this.phantom.ethereum.addEventListener("connect", (accounts) => {
1613
- this._accounts = accounts;
1614
- this.eventEmitter.emit("connect", { chainId: this._chainId });
1615
- this.eventEmitter.emit("accountsChanged", accounts);
1616
- });
1617
- this.phantom.ethereum.addEventListener("disconnect", () => {
1618
- this._accounts = [];
1619
- this.eventEmitter.emit("disconnect", { code: 4900, message: "Provider disconnected" });
1620
- this.eventEmitter.emit("accountsChanged", []);
1621
- });
1622
- this.phantom.ethereum.addEventListener("accountsChanged", (accounts) => {
1623
- this._accounts = accounts;
1624
- this.eventEmitter.emit("accountsChanged", accounts);
1625
- });
1626
- this.phantom.ethereum.addEventListener("chainChanged", (chainId) => {
1627
- this._chainId = chainId;
1628
- this.eventEmitter.emit("chainChanged", chainId);
1629
- });
1630
- }
1631
- // Event methods for interface compliance
1632
- on(event, listener) {
1633
- this.eventEmitter.on(event, listener);
1634
- }
1635
- off(event, listener) {
1636
- this.eventEmitter.off(event, listener);
1637
- }
1638
- };
1639
-
1640
1530
  // src/wallets/registry.ts
1641
1531
  function isPhantomWallet(wallet) {
1642
1532
  return wallet !== void 0 && wallet.id === "phantom" && "isPhantom" in wallet && wallet.isPhantom === true;
1643
1533
  }
1534
+ function isWalletStandardWallet(provider) {
1535
+ return provider !== null && typeof provider === "object" && "features" in provider && typeof provider.features === "object";
1536
+ }
1644
1537
  var InjectedWalletRegistry = class {
1645
1538
  constructor() {
1646
1539
  this.wallets = /* @__PURE__ */ new Map();
@@ -1649,8 +1542,7 @@ var InjectedWalletRegistry = class {
1649
1542
  register(info) {
1650
1543
  const wrappedProviders = {};
1651
1544
  if (info.providers?.solana) {
1652
- const isWalletStandard = info.providers.solana && typeof info.providers.solana === "object" && "features" in info.providers.solana && typeof info.providers.solana.features === "object";
1653
- if (isWalletStandard) {
1545
+ if (isWalletStandardWallet(info.providers.solana)) {
1654
1546
  wrappedProviders.solana = new WalletStandardSolanaAdapter(info.providers.solana, info.id, info.name);
1655
1547
  debug.log(DebugCategory.BROWSER_SDK, "Wrapped Wallet Standard Solana wallet with adapter", {
1656
1548
  walletId: info.id,
@@ -1680,26 +1572,26 @@ var InjectedWalletRegistry = class {
1680
1572
  /**
1681
1573
  * Register Phantom wallet with its instance
1682
1574
  * This creates wrapped providers and stores the Phantom instance for auto-confirm access
1575
+ * Uses unified InjectedWallet chains for both Phantom and external wallets
1683
1576
  */
1684
1577
  registerPhantom(phantomInstance, addressTypes) {
1685
1578
  const wrappedProviders = {};
1686
1579
  if (addressTypes.includes(import_client.AddressType.solana) && phantomInstance.solana) {
1687
- wrappedProviders.solana = new PhantomSolanaChain(phantomInstance);
1688
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomSolanaChain wrapper", {
1580
+ wrappedProviders.solana = new InjectedWalletSolanaChain(phantomInstance.solana, "phantom", "Phantom");
1581
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletSolanaChain wrapper for Phantom", {
1689
1582
  walletId: "phantom"
1690
1583
  });
1691
1584
  }
1692
1585
  if (addressTypes.includes(import_client.AddressType.ethereum) && phantomInstance.ethereum) {
1693
- wrappedProviders.ethereum = new PhantomEthereumChain(phantomInstance);
1694
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomEthereumChain wrapper", {
1586
+ wrappedProviders.ethereum = new InjectedWalletEthereumChain(phantomInstance.ethereum, "phantom", "Phantom");
1587
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletEthereumChain wrapper for Phantom", {
1695
1588
  walletId: "phantom"
1696
1589
  });
1697
1590
  }
1698
1591
  const phantomWallet = {
1699
1592
  id: "phantom",
1700
1593
  name: "Phantom",
1701
- icon: "",
1702
- // Icon will be rendered from icons package in UI components
1594
+ icon: import_constants2.PHANTOM_ICON,
1703
1595
  addressTypes,
1704
1596
  providers: wrappedProviders,
1705
1597
  isPhantom: true,
@@ -1776,15 +1668,16 @@ var WAS_CONNECTED_KEY = "phantom-injected-was-connected";
1776
1668
  var WAS_CONNECTED_VALUE = "true";
1777
1669
  var LAST_WALLET_ID_KEY = "phantom-injected-last-wallet-id";
1778
1670
  var InjectedProvider = class {
1779
- // Track which wallets have event listeners set up
1671
+ // Store cleanups per walletId
1780
1672
  constructor(config) {
1781
1673
  this.selectedWalletId = null;
1782
1674
  this.walletStates = /* @__PURE__ */ new Map();
1783
1675
  // Event management
1784
1676
  this.eventListeners = /* @__PURE__ */ new Map();
1785
- this.browserInjectedCleanupFunctions = [];
1786
1677
  this.eventsInitialized = false;
1787
- this.externalWalletEventListenersSetup = /* @__PURE__ */ new Set();
1678
+ this.eventListenersSetup = /* @__PURE__ */ new Set();
1679
+ // Track walletId that have listeners set up
1680
+ this.eventListenerCleanups = /* @__PURE__ */ new Map();
1788
1681
  debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
1789
1682
  this.addressTypes = config.addressTypes;
1790
1683
  this.walletRegistry = getWalletRegistry();
@@ -1815,9 +1708,12 @@ var InjectedProvider = class {
1815
1708
  });
1816
1709
  }
1817
1710
  }
1818
- get solana() {
1819
- if (!this.addressTypes.includes(import_client3.AddressType.solana)) {
1820
- throw new Error("Solana not enabled for this provider");
1711
+ /**
1712
+ * Helper method to get a chain provider with consistent error handling
1713
+ */
1714
+ getChainProvider(addressType, providerKey, chainName) {
1715
+ if (!this.addressTypes.includes(addressType)) {
1716
+ throw new Error(`${chainName} not enabled for this provider`);
1821
1717
  }
1822
1718
  const walletId = this.selectedWalletId || "phantom";
1823
1719
  const walletInfo = this.walletRegistry.getById(walletId);
@@ -1832,46 +1728,29 @@ var InjectedProvider = class {
1832
1728
  `Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
1833
1729
  );
1834
1730
  }
1835
- if (!walletInfo.providers?.solana) {
1731
+ const provider = walletInfo.providers?.[providerKey];
1732
+ if (!provider) {
1836
1733
  throw new Error(
1837
- `Selected wallet "${walletInfo.name}" does not support Solana. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Solana in addressTypes.`
1734
+ `Selected wallet "${walletInfo.name}" does not support ${chainName}. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes ${chainName} in addressTypes.`
1838
1735
  );
1839
1736
  }
1840
- return walletInfo.providers.solana;
1737
+ return provider;
1738
+ }
1739
+ get solana() {
1740
+ return this.getChainProvider(import_client4.AddressType.solana, "solana", "Solana");
1841
1741
  }
1842
1742
  /**
1843
1743
  * Access to Ethereum chain operations
1844
1744
  */
1845
1745
  get ethereum() {
1846
- if (!this.addressTypes.includes(import_client3.AddressType.ethereum)) {
1847
- throw new Error("Ethereum not enabled for this provider");
1848
- }
1849
- const walletId = this.selectedWalletId || "phantom";
1850
- const walletInfo = this.walletRegistry.getById(walletId);
1851
- if (!walletInfo) {
1852
- const registry = this.walletRegistry;
1853
- if (registry.discoveryPromise) {
1854
- throw new Error(
1855
- `Wallet "${walletId}" not found. Wallet discovery is still in progress. Please wait for sdk.discoverWallets() to complete before accessing chain properties.`
1856
- );
1857
- }
1858
- throw new Error(
1859
- `Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
1860
- );
1861
- }
1862
- if (!walletInfo.providers?.ethereum) {
1863
- throw new Error(
1864
- `Selected wallet "${walletInfo.name}" does not support Ethereum. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Ethereum in addressTypes.`
1865
- );
1866
- }
1867
- return walletInfo.providers.ethereum;
1868
- }
1869
- validateAndSelectWallet(requestedWalletId) {
1870
- if (!this.walletRegistry.has(requestedWalletId)) {
1871
- debug.error(DebugCategory.INJECTED_PROVIDER, "Unknown injected wallet id requested", {
1872
- walletId: requestedWalletId
1873
- });
1874
- throw new Error(`Unknown injected wallet id: ${requestedWalletId}`);
1746
+ return this.getChainProvider(import_client4.AddressType.ethereum, "ethereum", "Ethereum");
1747
+ }
1748
+ validateAndSelectWallet(requestedWalletId) {
1749
+ if (!this.walletRegistry.has(requestedWalletId)) {
1750
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Unknown injected wallet id requested", {
1751
+ walletId: requestedWalletId
1752
+ });
1753
+ throw new Error(`Unknown injected wallet id: ${requestedWalletId}`);
1875
1754
  }
1876
1755
  const walletInfo = this.walletRegistry.getById(requestedWalletId);
1877
1756
  if (!walletInfo || !walletInfo.providers) {
@@ -1902,16 +1781,10 @@ var InjectedProvider = class {
1902
1781
  options
1903
1782
  });
1904
1783
  if (!options?.skipEventListeners) {
1905
- this.setupExternalWalletEvents(walletInfo);
1906
- if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
1907
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
1908
- this.browserInjectedCleanupFunctions = [];
1909
- this.setupBrowserInjectedEvents();
1910
- this.eventsInitialized = true;
1911
- }
1784
+ this.setupEventListeners(walletInfo);
1912
1785
  }
1913
1786
  const connectedAddresses = [];
1914
- if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers?.solana) {
1787
+ if (this.addressTypes.includes(import_client4.AddressType.solana) && walletInfo.providers?.solana) {
1915
1788
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection", {
1916
1789
  walletId: this.selectedWalletId,
1917
1790
  walletName: walletInfo.name,
@@ -1923,7 +1796,7 @@ var InjectedProvider = class {
1923
1796
  );
1924
1797
  const address = result.publicKey;
1925
1798
  connectedAddresses.push({
1926
- addressType: import_client3.AddressType.solana,
1799
+ addressType: import_client4.AddressType.solana,
1927
1800
  address
1928
1801
  });
1929
1802
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", {
@@ -1944,7 +1817,7 @@ var InjectedProvider = class {
1944
1817
  throw err;
1945
1818
  }
1946
1819
  }
1947
- if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers?.ethereum) {
1820
+ if (this.addressTypes.includes(import_client4.AddressType.ethereum) && walletInfo.providers?.ethereum) {
1948
1821
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum connection", {
1949
1822
  walletId: this.selectedWalletId,
1950
1823
  walletName: walletInfo.name,
@@ -1960,7 +1833,7 @@ var InjectedProvider = class {
1960
1833
  if (accounts.length > 0) {
1961
1834
  connectedAddresses.push(
1962
1835
  ...accounts.map((address) => ({
1963
- addressType: import_client3.AddressType.ethereum,
1836
+ addressType: import_client4.AddressType.ethereum,
1964
1837
  address
1965
1838
  }))
1966
1839
  );
@@ -2040,7 +1913,8 @@ var InjectedProvider = class {
2040
1913
  this.emit("connect", {
2041
1914
  addresses: connectedAddresses,
2042
1915
  source: "manual-connect",
2043
- authUserId
1916
+ authUserId,
1917
+ walletId
2044
1918
  });
2045
1919
  return result;
2046
1920
  }
@@ -2052,12 +1926,13 @@ var InjectedProvider = class {
2052
1926
  if (authOptions.provider !== "injected") {
2053
1927
  throw new Error(`Invalid provider for injected connection: ${authOptions.provider}. Must be "injected"`);
2054
1928
  }
1929
+ const requestedWalletId = authOptions.walletId || "phantom";
2055
1930
  this.emit("connect_start", {
2056
1931
  source: "manual-connect",
2057
- providerType: "injected"
1932
+ providerType: "injected",
1933
+ walletId: requestedWalletId
2058
1934
  });
2059
1935
  try {
2060
- const requestedWalletId = authOptions.walletId || "phantom";
2061
1936
  const walletInfo = this.validateAndSelectWallet(requestedWalletId);
2062
1937
  const connectedAddresses = await this.connectToWallet(walletInfo);
2063
1938
  return await this.finalizeConnection(connectedAddresses, "injected", this.selectedWalletId || void 0);
@@ -2073,7 +1948,7 @@ var InjectedProvider = class {
2073
1948
  debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
2074
1949
  const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
2075
1950
  if (walletInfo?.providers) {
2076
- if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers.solana) {
1951
+ if (this.addressTypes.includes(import_client4.AddressType.solana) && walletInfo.providers.solana) {
2077
1952
  try {
2078
1953
  await walletInfo.providers.solana.disconnect();
2079
1954
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
@@ -2081,7 +1956,7 @@ var InjectedProvider = class {
2081
1956
  debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
2082
1957
  }
2083
1958
  }
2084
- if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers.ethereum) {
1959
+ if (this.addressTypes.includes(import_client4.AddressType.ethereum) && walletInfo.providers.ethereum) {
2085
1960
  try {
2086
1961
  await walletInfo.providers.ethereum.disconnect();
2087
1962
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
@@ -2090,10 +1965,14 @@ var InjectedProvider = class {
2090
1965
  }
2091
1966
  }
2092
1967
  }
2093
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
2094
- this.browserInjectedCleanupFunctions = [];
1968
+ const walletId = this.selectedWalletId || "phantom";
1969
+ const cleanups = this.eventListenerCleanups.get(walletId);
1970
+ if (cleanups) {
1971
+ cleanups.forEach((cleanup) => cleanup());
1972
+ this.eventListenerCleanups.delete(walletId);
1973
+ }
1974
+ this.eventListenersSetup.delete(walletId);
2095
1975
  if (this.selectedWalletId) {
2096
- this.externalWalletEventListenersSetup.delete(this.selectedWalletId);
2097
1976
  this.setWalletState(this.selectedWalletId, {
2098
1977
  connected: false,
2099
1978
  addresses: []
@@ -2162,13 +2041,7 @@ var InjectedProvider = class {
2162
2041
  });
2163
2042
  return;
2164
2043
  }
2165
- this.setupExternalWalletEvents(walletInfo);
2166
- if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
2167
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
2168
- this.browserInjectedCleanupFunctions = [];
2169
- this.setupBrowserInjectedEvents();
2170
- this.eventsInitialized = true;
2171
- }
2044
+ this.setupEventListeners(walletInfo);
2172
2045
  if (this.selectedWalletId) {
2173
2046
  this.setWalletState(this.selectedWalletId, {
2174
2047
  connected: true,
@@ -2179,7 +2052,8 @@ var InjectedProvider = class {
2179
2052
  this.emit("connect", {
2180
2053
  addresses: connectedAddresses,
2181
2054
  source: "auto-connect",
2182
- authUserId
2055
+ authUserId,
2056
+ walletId: this.selectedWalletId
2183
2057
  });
2184
2058
  debug.info(DebugCategory.INJECTED_PROVIDER, "Auto-connect successful", {
2185
2059
  addressCount: connectedAddresses.length,
@@ -2209,6 +2083,170 @@ var InjectedProvider = class {
2209
2083
  setWalletState(walletId, state) {
2210
2084
  this.walletStates.set(walletId, state);
2211
2085
  }
2086
+ /**
2087
+ * Update wallet state with new addresses for a specific address type
2088
+ * Replaces all existing addresses of the given type with the new addresses
2089
+ * @param walletId - The wallet ID to update
2090
+ * @param newAddresses - Array of new addresses (strings) for the address type
2091
+ * @param addressType - The type of addresses being updated
2092
+ * @returns The updated addresses array
2093
+ */
2094
+ updateWalletAddresses(walletId, newAddresses, addressType) {
2095
+ const state = this.getWalletState(walletId);
2096
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== addressType);
2097
+ const addressesOfType = newAddresses.map((address) => ({ addressType, address }));
2098
+ const updatedAddresses = [...otherAddresses, ...addressesOfType];
2099
+ this.setWalletState(walletId, {
2100
+ connected: updatedAddresses.length > 0,
2101
+ addresses: updatedAddresses
2102
+ });
2103
+ return updatedAddresses;
2104
+ }
2105
+ /**
2106
+ * Helper to construct account change source string
2107
+ */
2108
+ getAccountChangeSource(source) {
2109
+ return `${source}-account-change`;
2110
+ }
2111
+ /**
2112
+ * Create a handler for Solana connect events
2113
+ */
2114
+ createSolanaConnectHandler(walletId, source) {
2115
+ return async (publicKey) => {
2116
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey, walletId });
2117
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client4.AddressType.solana);
2118
+ const authUserId = await this.getAuthUserId("Solana connect event");
2119
+ this.emit("connect", {
2120
+ addresses: newAddresses,
2121
+ source,
2122
+ authUserId,
2123
+ walletId: this.selectedWalletId
2124
+ });
2125
+ };
2126
+ }
2127
+ /**
2128
+ * Create a handler for Solana disconnect events
2129
+ */
2130
+ createSolanaDisconnectHandler(walletId, source) {
2131
+ return () => {
2132
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received", { walletId });
2133
+ const state = this.getWalletState(walletId);
2134
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.solana);
2135
+ this.setWalletState(walletId, {
2136
+ connected: filteredAddresses.length > 0,
2137
+ addresses: filteredAddresses
2138
+ });
2139
+ this.emit("disconnect", {
2140
+ source
2141
+ });
2142
+ };
2143
+ }
2144
+ /**
2145
+ * Create a handler for Solana account change events
2146
+ * Can receive string | null per Wallet Standard
2147
+ */
2148
+ createSolanaAccountChangeHandler(walletId, source) {
2149
+ return async (publicKey) => {
2150
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey, walletId });
2151
+ if (publicKey) {
2152
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client4.AddressType.solana);
2153
+ const authUserId = await this.getAuthUserId("Solana account changed event");
2154
+ this.emit("connect", {
2155
+ addresses: newAddresses,
2156
+ source: this.getAccountChangeSource(source),
2157
+ authUserId,
2158
+ walletId: this.selectedWalletId
2159
+ });
2160
+ } else {
2161
+ const state = this.getWalletState(walletId);
2162
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.solana);
2163
+ this.setWalletState(walletId, {
2164
+ connected: otherAddresses.length > 0,
2165
+ addresses: otherAddresses
2166
+ });
2167
+ this.emit("disconnect", {
2168
+ source: this.getAccountChangeSource(source)
2169
+ });
2170
+ }
2171
+ };
2172
+ }
2173
+ /**
2174
+ * Create a handler for Ethereum connect events
2175
+ * EIP-1193 connect event receives { chainId: string }, but we need to get accounts separately
2176
+ */
2177
+ createEthereumConnectHandler(walletId, source) {
2178
+ return async (connectInfo) => {
2179
+ let accounts = [];
2180
+ if (Array.isArray(connectInfo)) {
2181
+ accounts = connectInfo;
2182
+ } else {
2183
+ try {
2184
+ const walletInfo = this.walletRegistry.getById(walletId);
2185
+ if (walletInfo?.providers?.ethereum) {
2186
+ accounts = await walletInfo.providers.ethereum.getAccounts();
2187
+ }
2188
+ } catch (error) {
2189
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to get accounts on connect", { error });
2190
+ }
2191
+ }
2192
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts, walletId });
2193
+ if (accounts.length > 0) {
2194
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client4.AddressType.ethereum);
2195
+ const authUserId = await this.getAuthUserId("Ethereum connect event");
2196
+ this.emit("connect", {
2197
+ addresses: newAddresses,
2198
+ source,
2199
+ authUserId,
2200
+ walletId: this.selectedWalletId
2201
+ });
2202
+ }
2203
+ };
2204
+ }
2205
+ /**
2206
+ * Create a handler for Ethereum disconnect events
2207
+ */
2208
+ createEthereumDisconnectHandler(walletId, source) {
2209
+ return () => {
2210
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received", { walletId });
2211
+ const state = this.getWalletState(walletId);
2212
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.ethereum);
2213
+ this.setWalletState(walletId, {
2214
+ connected: filteredAddresses.length > 0,
2215
+ addresses: filteredAddresses
2216
+ });
2217
+ this.emit("disconnect", {
2218
+ source
2219
+ });
2220
+ };
2221
+ }
2222
+ /**
2223
+ * Create a handler for Ethereum account change events
2224
+ */
2225
+ createEthereumAccountChangeHandler(walletId, source) {
2226
+ return async (accounts) => {
2227
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts, walletId });
2228
+ if (accounts && accounts.length > 0) {
2229
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client4.AddressType.ethereum);
2230
+ const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2231
+ this.emit("connect", {
2232
+ addresses: newAddresses,
2233
+ source: this.getAccountChangeSource(source),
2234
+ authUserId,
2235
+ walletId: this.selectedWalletId
2236
+ });
2237
+ } else {
2238
+ const state = this.getWalletState(walletId);
2239
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.ethereum);
2240
+ this.setWalletState(walletId, {
2241
+ connected: otherAddresses.length > 0,
2242
+ addresses: otherAddresses
2243
+ });
2244
+ this.emit("disconnect", {
2245
+ source: this.getAccountChangeSource(source)
2246
+ });
2247
+ }
2248
+ };
2249
+ }
2212
2250
  getAddresses() {
2213
2251
  const walletId = this.selectedWalletId || "phantom";
2214
2252
  return this.getWalletState(walletId).addresses;
@@ -2302,19 +2340,22 @@ var InjectedProvider = class {
2302
2340
  on(event, callback) {
2303
2341
  debug.log(DebugCategory.INJECTED_PROVIDER, "Adding event listener", { event });
2304
2342
  if (!this.eventsInitialized) {
2305
- this.setupBrowserInjectedEvents();
2306
- this.eventsInitialized = true;
2343
+ const walletId = this.selectedWalletId || "phantom";
2344
+ const walletInfo = this.walletRegistry.getById(walletId);
2345
+ if (walletInfo) {
2346
+ this.setupEventListeners(walletInfo);
2347
+ }
2307
2348
  }
2308
2349
  if (!this.eventListeners.has(event)) {
2309
2350
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
2310
2351
  }
2311
- this.eventListeners.get(event).add(callback);
2352
+ this.eventListeners.get(event)?.add(callback);
2312
2353
  }
2313
2354
  off(event, callback) {
2314
2355
  debug.log(DebugCategory.INJECTED_PROVIDER, "Removing event listener", { event });
2315
2356
  if (this.eventListeners.has(event)) {
2316
- this.eventListeners.get(event).delete(callback);
2317
- if (this.eventListeners.get(event).size === 0) {
2357
+ this.eventListeners.get(event)?.delete(callback);
2358
+ if (this.eventListeners.get(event)?.size === 0) {
2318
2359
  this.eventListeners.delete(event);
2319
2360
  }
2320
2361
  }
@@ -2336,246 +2377,89 @@ var InjectedProvider = class {
2336
2377
  });
2337
2378
  }
2338
2379
  }
2339
- setupBrowserInjectedEvents() {
2340
- const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
2341
- if (!isPhantomWallet(walletInfo)) {
2342
- debug.log(DebugCategory.INJECTED_PROVIDER, "Skipping browser-injected-sdk event setup - not Phantom wallet");
2380
+ /**
2381
+ * Set up Solana event listeners for any provider (Phantom or external)
2382
+ */
2383
+ setupSolanaEventListeners(provider, walletId, source) {
2384
+ if (typeof provider.on !== "function")
2343
2385
  return;
2344
- }
2345
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
2346
- if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
2347
- if (this.addressTypes.includes(import_client3.AddressType.solana)) {
2348
- this.setupSolanaEvents(walletInfo.phantomInstance);
2349
- }
2350
- if (this.addressTypes.includes(import_client3.AddressType.ethereum)) {
2351
- this.setupEthereumEvents(walletInfo.phantomInstance);
2352
- }
2353
- }
2354
- }
2355
- setupSolanaEvents(phantom) {
2356
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
2357
- const handleSolanaConnect = async (publicKey) => {
2358
- debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
2359
- const walletId = this.selectedWalletId || "phantom";
2360
- const state = this.getWalletState(walletId);
2361
- const solanaAddress = { addressType: import_client3.AddressType.solana, address: publicKey };
2362
- const hasSolana = state.addresses.some((addr) => addr.addressType === import_client3.AddressType.solana);
2363
- const newAddresses = hasSolana ? state.addresses.map((addr) => addr.addressType === import_client3.AddressType.solana ? solanaAddress : addr) : [...state.addresses, solanaAddress];
2364
- this.setWalletState(walletId, {
2365
- connected: true,
2366
- addresses: newAddresses
2367
- });
2368
- const authUserId = await this.getAuthUserId("Solana connect event");
2369
- this.emit("connect", {
2370
- addresses: newAddresses,
2371
- source: "injected-extension",
2372
- authUserId
2373
- });
2386
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners", { walletId, source });
2387
+ const handlers = {
2388
+ connect: this.createSolanaConnectHandler(walletId, source),
2389
+ disconnect: this.createSolanaDisconnectHandler(walletId, source),
2390
+ accountChanged: this.createSolanaAccountChangeHandler(walletId, source)
2374
2391
  };
2375
- const handleSolanaDisconnect = () => {
2376
- debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
2377
- const walletId = this.selectedWalletId || "phantom";
2378
- const state = this.getWalletState(walletId);
2379
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
2380
- this.setWalletState(walletId, {
2381
- connected: filteredAddresses.length > 0,
2382
- addresses: filteredAddresses
2383
- });
2384
- this.emit("disconnect", {
2385
- source: "injected-extension"
2386
- });
2387
- };
2388
- const handleSolanaAccountChanged = async (publicKey) => {
2389
- debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
2390
- const walletId = this.selectedWalletId || "phantom";
2391
- const state = this.getWalletState(walletId);
2392
- const solanaIndex = state.addresses.findIndex((addr) => addr.addressType === import_client3.AddressType.solana);
2393
- const newAddresses = solanaIndex >= 0 ? state.addresses.map(
2394
- (addr, idx) => idx === solanaIndex ? { addressType: import_client3.AddressType.solana, address: publicKey } : addr
2395
- ) : [...state.addresses, { addressType: import_client3.AddressType.solana, address: publicKey }];
2396
- this.setWalletState(walletId, {
2397
- connected: true,
2398
- addresses: newAddresses
2399
- });
2400
- const authUserId = await this.getAuthUserId("Solana account changed event");
2401
- this.emit("connect", {
2402
- addresses: newAddresses,
2403
- source: "injected-extension-account-change",
2404
- authUserId
2405
- });
2406
- };
2407
- const cleanupConnect = phantom.solana.addEventListener("connect", handleSolanaConnect);
2408
- const cleanupDisconnect = phantom.solana.addEventListener("disconnect", handleSolanaDisconnect);
2409
- const cleanupAccountChanged = phantom.solana.addEventListener("accountChanged", handleSolanaAccountChanged);
2410
- this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountChanged);
2411
- }
2412
- setupEthereumEvents(phantom) {
2413
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
2414
- const handleEthereumConnect = async (accounts) => {
2415
- debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
2416
- const walletId = this.selectedWalletId || "phantom";
2417
- const state = this.getWalletState(walletId);
2418
- const ethAddresses = accounts.map((address) => ({ addressType: import_client3.AddressType.ethereum, address }));
2419
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2420
- const newAddresses = [...otherAddresses, ...ethAddresses];
2421
- this.setWalletState(walletId, {
2422
- connected: true,
2423
- addresses: newAddresses
2424
- });
2425
- const authUserId = await this.getAuthUserId("Ethereum connect event");
2426
- this.emit("connect", {
2427
- addresses: newAddresses,
2428
- source: "injected-extension",
2429
- authUserId
2430
- });
2431
- };
2432
- const handleEthereumDisconnect = () => {
2433
- debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
2434
- const walletId = this.selectedWalletId || "phantom";
2435
- const state = this.getWalletState(walletId);
2436
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2437
- this.setWalletState(walletId, {
2438
- connected: filteredAddresses.length > 0,
2439
- addresses: filteredAddresses
2440
- });
2441
- this.emit("disconnect", {
2442
- source: "injected-extension"
2443
- });
2444
- };
2445
- const handleEthereumAccountsChanged = async (accounts) => {
2446
- debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts });
2447
- const walletId = this.selectedWalletId || "phantom";
2448
- const state = this.getWalletState(walletId);
2449
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2450
- if (accounts && accounts.length > 0) {
2451
- const ethAddresses = accounts.map((address) => ({ addressType: import_client3.AddressType.ethereum, address }));
2452
- const newAddresses = [...otherAddresses, ...ethAddresses];
2453
- this.setWalletState(walletId, {
2454
- connected: true,
2455
- addresses: newAddresses
2456
- });
2457
- const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2458
- this.emit("connect", {
2459
- addresses: newAddresses,
2460
- source: "injected-extension-account-change",
2461
- authUserId
2462
- });
2463
- } else {
2464
- this.setWalletState(walletId, {
2465
- connected: otherAddresses.length > 0,
2466
- addresses: otherAddresses
2467
- });
2468
- this.emit("disconnect", {
2469
- source: "injected-extension-account-change"
2470
- });
2471
- }
2472
- };
2473
- const cleanupConnect = phantom.ethereum.addEventListener("connect", handleEthereumConnect);
2474
- const cleanupDisconnect = phantom.ethereum.addEventListener("disconnect", handleEthereumDisconnect);
2475
- const cleanupAccountsChanged = phantom.ethereum.addEventListener("accountsChanged", handleEthereumAccountsChanged);
2476
- this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountsChanged);
2392
+ provider.on("connect", handlers.connect);
2393
+ provider.on("disconnect", handlers.disconnect);
2394
+ provider.on("accountChanged", handlers.accountChanged);
2395
+ const cleanups = [];
2396
+ if (typeof provider.off === "function") {
2397
+ cleanups.push(
2398
+ () => provider.off("connect", handlers.connect),
2399
+ () => provider.off("disconnect", handlers.disconnect),
2400
+ () => provider.off("accountChanged", handlers.accountChanged)
2401
+ );
2402
+ }
2403
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2404
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2477
2405
  }
2478
- setupExternalWalletEvents(walletInfo) {
2479
- if (isPhantomWallet(walletInfo)) {
2406
+ /**
2407
+ * Set up Ethereum event listeners for any provider (Phantom or external)
2408
+ */
2409
+ setupEthereumEventListeners(provider, walletId, source) {
2410
+ if (typeof provider.on !== "function")
2480
2411
  return;
2412
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners", { walletId, source });
2413
+ const handlers = {
2414
+ connect: this.createEthereumConnectHandler(walletId, source),
2415
+ disconnect: this.createEthereumDisconnectHandler(walletId, source),
2416
+ accountsChanged: this.createEthereumAccountChangeHandler(walletId, source)
2417
+ };
2418
+ provider.on("connect", handlers.connect);
2419
+ provider.on("disconnect", handlers.disconnect);
2420
+ provider.on("accountsChanged", handlers.accountsChanged);
2421
+ const cleanups = [];
2422
+ if (typeof provider.off === "function") {
2423
+ cleanups.push(
2424
+ () => provider.off("connect", handlers.connect),
2425
+ () => provider.off("disconnect", handlers.disconnect),
2426
+ () => provider.off("accountsChanged", handlers.accountsChanged)
2427
+ );
2481
2428
  }
2482
- if (!this.selectedWalletId || this.externalWalletEventListenersSetup.has(this.selectedWalletId)) {
2429
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2430
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2431
+ }
2432
+ /**
2433
+ * Unified event listener setup for all wallet types (Phantom and external).
2434
+ * Cleans up listeners for previously selected wallets to prevent stale events
2435
+ * from causing walletId flicker during connections.
2436
+ */
2437
+ setupEventListeners(walletInfo) {
2438
+ const walletId = this.selectedWalletId || "phantom";
2439
+ if (this.eventListenersSetup.has(walletId)) {
2440
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Event listeners already set up for wallet", { walletId });
2483
2441
  return;
2484
2442
  }
2485
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up external wallet event listeners", {
2486
- walletId: this.selectedWalletId
2487
- });
2488
- if (walletInfo.providers?.ethereum) {
2489
- const handleExternalEthereumAccountsChanged = async (accounts) => {
2490
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum accounts changed event received", {
2491
- walletId: this.selectedWalletId,
2492
- accounts
2493
- });
2494
- const walletId = this.selectedWalletId;
2495
- const state = this.getWalletState(walletId);
2496
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2497
- if (accounts && accounts.length > 0) {
2498
- const ethAddresses = accounts.map((address) => ({ addressType: import_client3.AddressType.ethereum, address }));
2499
- const newAddresses = [...otherAddresses, ...ethAddresses];
2500
- this.setWalletState(walletId, {
2501
- connected: true,
2502
- addresses: newAddresses
2503
- });
2504
- debug.log(DebugCategory.INJECTED_PROVIDER, "Updated Ethereum addresses after account change", {
2505
- walletId,
2506
- oldCount: 0,
2507
- // We filtered them out
2508
- newCount: accounts.length,
2509
- addresses: newAddresses.filter((addr) => addr.addressType === import_client3.AddressType.ethereum)
2510
- });
2511
- const authUserId = await this.getAuthUserId("External wallet Ethereum accounts changed event");
2512
- this.emit("connect", {
2513
- addresses: newAddresses,
2514
- source: "external-wallet-account-change",
2515
- authUserId
2516
- });
2517
- } else {
2518
- this.setWalletState(walletId, {
2519
- connected: otherAddresses.length > 0,
2520
- addresses: otherAddresses
2521
- });
2522
- this.emit("disconnect", {
2523
- source: "external-wallet-account-change"
2524
- });
2525
- }
2526
- };
2527
- if (typeof walletInfo.providers.ethereum.on === "function") {
2528
- walletInfo.providers.ethereum.on("accountsChanged", handleExternalEthereumAccountsChanged);
2529
- this.browserInjectedCleanupFunctions.push(() => {
2530
- if (typeof walletInfo.providers?.ethereum?.off === "function") {
2531
- walletInfo.providers.ethereum.off("accountsChanged", handleExternalEthereumAccountsChanged);
2532
- }
2533
- });
2443
+ for (const existingWalletId of this.eventListenersSetup) {
2444
+ if (existingWalletId === walletId) {
2445
+ continue;
2534
2446
  }
2535
- }
2536
- if (walletInfo.providers?.solana) {
2537
- const handleExternalSolanaAccountChanged = async (publicKey) => {
2538
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana account changed event received", {
2539
- walletId: this.selectedWalletId,
2540
- publicKey
2541
- });
2542
- const walletId = this.selectedWalletId;
2543
- const state = this.getWalletState(walletId);
2544
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
2545
- if (publicKey) {
2546
- const newAddresses = [...otherAddresses, { addressType: import_client3.AddressType.solana, address: publicKey }];
2547
- this.setWalletState(walletId, {
2548
- connected: true,
2549
- addresses: newAddresses
2550
- });
2551
- const authUserId = await this.getAuthUserId("External wallet Solana account changed event");
2552
- this.emit("connect", {
2553
- addresses: newAddresses,
2554
- source: "external-wallet-account-change",
2555
- authUserId
2556
- });
2557
- } else {
2558
- this.setWalletState(walletId, {
2559
- connected: otherAddresses.length > 0,
2560
- addresses: otherAddresses
2561
- });
2562
- this.emit("disconnect", {
2563
- source: "external-wallet-account-change"
2564
- });
2565
- }
2566
- };
2567
- if (typeof walletInfo.providers.solana.on === "function") {
2568
- walletInfo.providers.solana.on("accountChanged", handleExternalSolanaAccountChanged);
2569
- this.browserInjectedCleanupFunctions.push(() => {
2570
- if (typeof walletInfo.providers?.solana?.off === "function") {
2571
- walletInfo.providers.solana.off("accountChanged", handleExternalSolanaAccountChanged);
2572
- }
2573
- });
2447
+ const cleanups = this.eventListenerCleanups.get(existingWalletId);
2448
+ if (cleanups) {
2449
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Cleaning up event listeners for wallet", { existingWalletId });
2450
+ cleanups.forEach((cleanup) => cleanup());
2574
2451
  }
2452
+ this.eventListenersSetup.delete(existingWalletId);
2575
2453
  }
2576
- if (this.selectedWalletId) {
2577
- this.externalWalletEventListenersSetup.add(this.selectedWalletId);
2454
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up event listeners", { walletId });
2455
+ if (this.addressTypes.includes(import_client4.AddressType.solana) && walletInfo.providers?.solana) {
2456
+ this.setupSolanaEventListeners(walletInfo.providers.solana, walletId, "wallet");
2457
+ }
2458
+ if (this.addressTypes.includes(import_client4.AddressType.ethereum) && walletInfo.providers?.ethereum) {
2459
+ this.setupEthereumEventListeners(walletInfo.providers.ethereum, walletId, "wallet");
2578
2460
  }
2461
+ this.eventListenersSetup.add(walletId);
2462
+ this.eventsInitialized = true;
2579
2463
  }
2580
2464
  };
2581
2465
 
@@ -2715,7 +2599,7 @@ var BrowserURLParamsAccessor = class {
2715
2599
  var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
2716
2600
 
2717
2601
  // src/providers/embedded/adapters/auth.ts
2718
- var import_constants = require("@phantom/constants");
2602
+ var import_constants3 = require("@phantom/constants");
2719
2603
 
2720
2604
  // src/utils/browser-detection.ts
2721
2605
  function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
@@ -2880,7 +2764,7 @@ var BrowserAuthProvider = class {
2880
2764
  provider: phantomOptions.provider,
2881
2765
  authUrl: phantomOptions.authUrl
2882
2766
  });
2883
- const baseUrl = phantomOptions.authUrl || import_constants.DEFAULT_AUTH_URL;
2767
+ const baseUrl = phantomOptions.authUrl || import_constants3.DEFAULT_AUTH_URL;
2884
2768
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
2885
2769
  const params = new URLSearchParams({
2886
2770
  public_key: phantomOptions.publicKey,
@@ -2890,9 +2774,10 @@ var BrowserAuthProvider = class {
2890
2774
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2891
2775
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2892
2776
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2893
- sdk_version: "1.0.0",
2777
+ sdk_version: "1.0.3",
2894
2778
  sdk_type: "browser",
2895
- platform: detectBrowser().name
2779
+ platform: detectBrowser().name,
2780
+ algorithm: phantomOptions.algorithm || import_constants3.DEFAULT_AUTHENTICATOR_ALGORITHM
2896
2781
  });
2897
2782
  if (phantomOptions.provider) {
2898
2783
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
@@ -3013,28 +2898,9 @@ var BrowserAuthProvider = class {
3013
2898
  // src/providers/embedded/adapters/phantom-app.ts
3014
2899
  var import_browser_injected_sdk4 = require("@phantom/browser-injected-sdk");
3015
2900
 
3016
- // src/isPhantomLoginAvailable.ts
2901
+ // src/waitForPhantomExtension.ts
3017
2902
  var import_browser_injected_sdk3 = require("@phantom/browser-injected-sdk");
3018
- async function isPhantomLoginAvailable(timeoutMs = 3e3) {
3019
- const extensionInstalled = await waitForExtension(timeoutMs);
3020
- if (!extensionInstalled) {
3021
- return false;
3022
- }
3023
- try {
3024
- if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
3025
- return false;
3026
- }
3027
- const response = await window.phantom.app.features();
3028
- if (!Array.isArray(response.features)) {
3029
- return false;
3030
- }
3031
- return response.features.includes("phantom_login");
3032
- } catch (error) {
3033
- console.error("Error checking Phantom extension features", error);
3034
- return false;
3035
- }
3036
- }
3037
- async function waitForExtension(timeoutMs) {
2903
+ async function waitForPhantomExtension(timeoutMs = 3e3) {
3038
2904
  return new Promise((resolve) => {
3039
2905
  const startTime = Date.now();
3040
2906
  const checkInterval = 100;
@@ -3057,6 +2923,27 @@ async function waitForExtension(timeoutMs) {
3057
2923
  });
3058
2924
  }
3059
2925
 
2926
+ // src/isPhantomLoginAvailable.ts
2927
+ async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2928
+ const extensionInstalled = await waitForPhantomExtension(timeoutMs);
2929
+ if (!extensionInstalled) {
2930
+ return false;
2931
+ }
2932
+ try {
2933
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2934
+ return false;
2935
+ }
2936
+ const response = await window.phantom.app.features();
2937
+ if (!Array.isArray(response.features)) {
2938
+ return false;
2939
+ }
2940
+ return response.features.includes("phantom_login");
2941
+ } catch (error) {
2942
+ console.error("Error checking Phantom extension features", error);
2943
+ return false;
2944
+ }
2945
+ }
2946
+
3060
2947
  // src/providers/embedded/adapters/phantom-app.ts
3061
2948
  var BrowserPhantomAppProvider = class {
3062
2949
  /**
@@ -3126,7 +3013,7 @@ var BrowserLogger = class {
3126
3013
  };
3127
3014
 
3128
3015
  // src/providers/embedded/index.ts
3129
- var import_constants2 = require("@phantom/constants");
3016
+ var import_constants4 = require("@phantom/constants");
3130
3017
  var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
3131
3018
  constructor(config) {
3132
3019
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
@@ -3147,14 +3034,14 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
3147
3034
  name: platformName,
3148
3035
  // Use detected browser name and version for identification
3149
3036
  analyticsHeaders: {
3150
- [import_constants2.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
3151
- [import_constants2.ANALYTICS_HEADERS.PLATFORM]: browserName,
3037
+ [import_constants4.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
3038
+ [import_constants4.ANALYTICS_HEADERS.PLATFORM]: browserName,
3152
3039
  // firefox, chrome, safari, etc.
3153
- [import_constants2.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
3040
+ [import_constants4.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
3154
3041
  // Full user agent for more detailed info
3155
- [import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
3156
- [import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3157
- [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0"
3042
+ [import_constants4.ANALYTICS_HEADERS.APP_ID]: config.appId,
3043
+ [import_constants4.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3044
+ [import_constants4.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.3"
3158
3045
  // Replaced at build time
3159
3046
  }
3160
3047
  };
@@ -3171,7 +3058,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
3171
3058
 
3172
3059
  // src/ProviderManager.ts
3173
3060
  var import_embedded_provider_core2 = require("@phantom/embedded-provider-core");
3174
- var import_constants3 = require("@phantom/constants");
3061
+ var import_constants5 = require("@phantom/constants");
3175
3062
 
3176
3063
  // src/utils/auth-callback.ts
3177
3064
  function isAuthFailureCallback(searchParams) {
@@ -3191,11 +3078,12 @@ function isAuthCallbackUrl(searchParams) {
3191
3078
  }
3192
3079
 
3193
3080
  // src/utils/deeplink.ts
3194
- function getDeeplinkToPhantom(ref) {
3195
- if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
3081
+ function getDeeplinkToPhantom(ref, currentHref) {
3082
+ const resolvedHref = currentHref ?? window.location.href;
3083
+ if (!resolvedHref.startsWith("http:") && !resolvedHref.startsWith("https:")) {
3196
3084
  throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
3197
3085
  }
3198
- const currentUrl = encodeURIComponent(window.location.href);
3086
+ const currentUrl = encodeURIComponent(resolvedHref);
3199
3087
  const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
3200
3088
  return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
3201
3089
  }
@@ -3291,8 +3179,14 @@ var ProviderManager = class {
3291
3179
  } else if (requestedProvider === "deeplink") {
3292
3180
  try {
3293
3181
  const deeplinkUrl = getDeeplinkToPhantom();
3294
- if (typeof window !== "undefined") {
3295
- window.location.href = deeplinkUrl;
3182
+ if (typeof window !== "undefined" && window.location) {
3183
+ try {
3184
+ window.location.href = deeplinkUrl;
3185
+ } catch (error) {
3186
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "Failed to set deeplink location", {
3187
+ error: error instanceof Error ? error.message : String(error)
3188
+ });
3189
+ }
3296
3190
  }
3297
3191
  return {
3298
3192
  addresses: [],
@@ -3437,7 +3331,7 @@ var ProviderManager = class {
3437
3331
  if (!this.eventListeners.has(event)) {
3438
3332
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
3439
3333
  }
3440
- this.eventListeners.get(event).add(callback);
3334
+ this.eventListeners.get(event)?.add(callback);
3441
3335
  this.ensureProviderEventForwarding();
3442
3336
  }
3443
3337
  /**
@@ -3446,8 +3340,8 @@ var ProviderManager = class {
3446
3340
  off(event, callback) {
3447
3341
  debug.log(DebugCategory.PROVIDER_MANAGER, "Removing event listener", { event });
3448
3342
  if (this.eventListeners.has(event)) {
3449
- this.eventListeners.get(event).delete(callback);
3450
- if (this.eventListeners.get(event).size === 0) {
3343
+ this.eventListeners.get(event)?.delete(callback);
3344
+ if (this.eventListeners.get(event)?.size === 0) {
3451
3345
  this.eventListeners.delete(event);
3452
3346
  }
3453
3347
  }
@@ -3555,8 +3449,8 @@ var ProviderManager = class {
3555
3449
  if (!this.config.appId) {
3556
3450
  throw new Error("appId is required for embedded provider");
3557
3451
  }
3558
- const apiBaseUrl = this.config.apiBaseUrl || import_constants3.DEFAULT_WALLET_API_URL;
3559
- const authUrl = this.config.authOptions?.authUrl || import_constants3.DEFAULT_AUTH_URL;
3452
+ const apiBaseUrl = this.config.apiBaseUrl || import_constants5.DEFAULT_WALLET_API_URL;
3453
+ const authUrl = this.config.authOptions?.authUrl || import_constants5.DEFAULT_AUTH_URL;
3560
3454
  provider = new EmbeddedProvider({
3561
3455
  apiBaseUrl,
3562
3456
  appId: this.config.appId,
@@ -3565,7 +3459,7 @@ var ProviderManager = class {
3565
3459
  authUrl,
3566
3460
  redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
3567
3461
  },
3568
- embeddedWalletType: embeddedWalletType || import_constants3.DEFAULT_EMBEDDED_WALLET_TYPE,
3462
+ embeddedWalletType: embeddedWalletType || import_constants5.DEFAULT_EMBEDDED_WALLET_TYPE,
3569
3463
  addressTypes: this.config.addressTypes || [import_client.AddressType.solana]
3570
3464
  });
3571
3465
  } else {
@@ -3601,7 +3495,7 @@ var ProviderManager = class {
3601
3495
 
3602
3496
  // src/BrowserSDK.ts
3603
3497
  var import_embedded_provider_core3 = require("@phantom/embedded-provider-core");
3604
- var import_constants4 = require("@phantom/constants");
3498
+ var import_constants6 = require("@phantom/constants");
3605
3499
  var BROWSER_SDK_PROVIDER_TYPES = [
3606
3500
  ...import_embedded_provider_core3.EMBEDDED_PROVIDER_AUTH_TYPES,
3607
3501
  "injected",
@@ -3637,7 +3531,7 @@ var BrowserSDK = class {
3637
3531
  });
3638
3532
  throw new Error("appId is required when using embedded providers (google, apple, phantom, etc.)");
3639
3533
  }
3640
- const embeddedWalletType = config.embeddedWalletType || import_constants4.DEFAULT_EMBEDDED_WALLET_TYPE;
3534
+ const embeddedWalletType = config.embeddedWalletType || import_constants6.DEFAULT_EMBEDDED_WALLET_TYPE;
3641
3535
  if (!["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
3642
3536
  debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
3643
3537
  embeddedWalletType: config.embeddedWalletType
@@ -3763,6 +3657,7 @@ var BrowserSDK = class {
3763
3657
  */
3764
3658
  async autoConnect() {
3765
3659
  debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect with fallback strategy");
3660
+ await this.discoverWallets();
3766
3661
  const result = await this.providerManager.autoConnect();
3767
3662
  if (result) {
3768
3663
  debug.info(DebugCategory.BROWSER_SDK, "Auto-connect successful", {
@@ -3910,31 +3805,7 @@ var BrowserSDK = class {
3910
3805
  }
3911
3806
  };
3912
3807
 
3913
- // src/waitForPhantomExtension.ts
3914
- var import_browser_injected_sdk5 = require("@phantom/browser-injected-sdk");
3915
- async function waitForPhantomExtension(timeoutMs = 3e3) {
3916
- return new Promise((resolve) => {
3917
- const startTime = Date.now();
3918
- const checkInterval = 100;
3919
- const checkForExtension = () => {
3920
- try {
3921
- if ((0, import_browser_injected_sdk5.isPhantomExtensionInstalled)()) {
3922
- resolve(true);
3923
- return;
3924
- }
3925
- } catch (error) {
3926
- }
3927
- const elapsed = Date.now() - startTime;
3928
- if (elapsed >= timeoutMs) {
3929
- resolve(false);
3930
- return;
3931
- }
3932
- setTimeout(checkForExtension, checkInterval);
3933
- };
3934
- checkForExtension();
3935
- });
3936
- }
3937
-
3938
3808
  // src/index.ts
3939
- var import_constants5 = require("@phantom/constants");
3940
- var import_client4 = require("@phantom/client");
3809
+ var import_constants7 = require("@phantom/constants");
3810
+ var import_client5 = require("@phantom/client");
3811
+ var import_constants8 = require("@phantom/constants");