@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.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { AddressType } from "@phantom/client";
3
3
 
4
4
  // src/providers/injected/index.ts
5
- import { AddressType as AddressType2 } from "@phantom/client";
5
+ import { AddressType as AddressType3 } from "@phantom/client";
6
6
 
7
7
  // src/debug.ts
8
8
  var DebugLevel = /* @__PURE__ */ ((DebugLevel2) => {
@@ -79,12 +79,27 @@ var DebugCategory = {
79
79
  };
80
80
 
81
81
  // src/wallets/discovery.ts
82
+ import { PHANTOM_ICON } from "@phantom/constants";
82
83
  import { AddressType as ClientAddressType } from "@phantom/client";
83
84
  import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
84
85
  import { createPhantom, createExtensionPlugin } from "@phantom/browser-injected-sdk";
85
86
  import { createSolanaPlugin } from "@phantom/browser-injected-sdk/solana";
86
87
  import { createEthereumPlugin } from "@phantom/browser-injected-sdk/ethereum";
87
88
  import { createAutoConfirmPlugin } from "@phantom/browser-injected-sdk/auto-confirm";
89
+
90
+ // src/wallets/custom-wallets.ts
91
+ import { AddressType as AddressType2 } from "@phantom/client";
92
+ var CUSTOM_WALLET_CONFIGS = [
93
+ {
94
+ id: "coinbase-wallet",
95
+ name: "Coinbase Wallet",
96
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTI4IDU2YzE1LjQ2NCAwIDI4LTEyLjUzNiAyOC0yOFM0My40NjQgMCAyOCAwIDAgMTIuNTM2IDAgMjhzMTIuNTM2IDI4IDI4IDI4WiIgZmlsbD0iIzFCNTNFNCIvPjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNyAyOGMwIDExLjU5OCA5LjQwMiAyMSAyMSAyMXMyMS05LjQwMiAyMS0yMVMzOS41OTggNyAyOCA3IDcgMTYuNDAyIDcgMjhabTE3LjIzNC02Ljc2NmEzIDMgMCAwIDAtMyAzdjcuNTMzYTMgMyAwIDAgMCAzIDNoNy41MzNhMyAzIDAgMCAwIDMtM3YtNy41MzNhMyAzIDAgMCAwLTMtM2gtNy41MzNaIiBmaWxsPSIjZmZmIi8+PC9zdmc+",
97
+ windowProperty: "coinbaseSolana",
98
+ addressTypes: [AddressType2.solana]
99
+ }
100
+ ];
101
+
102
+ // src/wallets/discovery.ts
88
103
  function generateWalletIdFromEIP6963(info) {
89
104
  if (info.rdns) {
90
105
  return info.rdns.split(".").reverse().join("-");
@@ -297,7 +312,7 @@ async function discoverSolanaWallets() {
297
312
  return chainLower.startsWith("solana:") || chainLower === "solana";
298
313
  }) || wallet.features && typeof wallet.features === "object" && Object.keys(wallet.features).some((featureKey) => {
299
314
  const featureLower = featureKey.toLowerCase();
300
- return featureLower.includes("solana") || featureLower.includes("standard:connect") || featureLower.includes("standard:signTransaction");
315
+ return featureLower.startsWith("solana:");
301
316
  });
302
317
  if (!supportsSolana) {
303
318
  const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
@@ -348,6 +363,51 @@ async function discoverSolanaWallets() {
348
363
  walletNames: wallets.map((w) => w.name)
349
364
  };
350
365
  debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard Solana discovery completed", finalLogData);
366
+ const customWallets = discoverCustomSolanaWallets();
367
+ wallets.push(...customWallets);
368
+ return wallets;
369
+ }
370
+ function discoverCustomSolanaWallets() {
371
+ const wallets = [];
372
+ if (typeof window === "undefined") {
373
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet discovery skipped (not in browser environment)");
374
+ return wallets;
375
+ }
376
+ debug.log(DebugCategory.BROWSER_SDK, "Starting custom Solana wallet discovery", {
377
+ configCount: CUSTOM_WALLET_CONFIGS.length
378
+ });
379
+ for (const config of CUSTOM_WALLET_CONFIGS) {
380
+ if (!config.addressTypes.includes(ClientAddressType.solana)) {
381
+ continue;
382
+ }
383
+ const provider = window[config.windowProperty];
384
+ if (!provider) {
385
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet not found", {
386
+ walletId: config.id,
387
+ windowProperty: config.windowProperty
388
+ });
389
+ continue;
390
+ }
391
+ debug.log(DebugCategory.BROWSER_SDK, "Discovered custom Solana wallet", {
392
+ walletId: config.id,
393
+ walletName: config.name,
394
+ windowProperty: config.windowProperty
395
+ });
396
+ wallets.push({
397
+ id: config.id,
398
+ name: config.name,
399
+ icon: config.icon,
400
+ addressTypes: config.addressTypes,
401
+ providers: {
402
+ solana: provider
403
+ },
404
+ discovery: "custom"
405
+ });
406
+ }
407
+ debug.log(DebugCategory.BROWSER_SDK, "Custom Solana wallet discovery completed", {
408
+ discoveredCount: wallets.length,
409
+ walletIds: wallets.map((w) => w.id)
410
+ });
351
411
  return wallets;
352
412
  }
353
413
  function discoverPhantomWallet(addressTypes) {
@@ -369,8 +429,7 @@ function discoverPhantomWallet(addressTypes) {
369
429
  return {
370
430
  id: "phantom",
371
431
  name: "Phantom",
372
- icon: void 0,
373
- // Icon will be rendered from icons package in UI components
432
+ icon: PHANTOM_ICON,
374
433
  addressTypes,
375
434
  providers: {
376
435
  solana: addressTypes.includes(ClientAddressType.solana) ? phantomInstance.solana : void 0,
@@ -439,67 +498,65 @@ async function discoverWallets(addressTypes) {
439
498
  return Array.from(walletMap.values());
440
499
  }
441
500
 
501
+ // src/wallets/registry.ts
502
+ import { PHANTOM_ICON as PHANTOM_ICON2 } from "@phantom/constants";
503
+
442
504
  // src/providers/injected/chains/InjectedWalletSolanaChain.ts
443
505
  import { EventEmitter } from "eventemitter3";
444
- import { Buffer as Buffer2 } from "buffer";
506
+ import { Buffer } from "buffer";
445
507
  var InjectedWalletSolanaChain = class {
446
508
  constructor(provider, walletId, walletName) {
509
+ // Expose eventEmitter for testing - allows tests to trigger events directly
447
510
  this.eventEmitter = new EventEmitter();
448
- this._connected = false;
449
511
  this._publicKey = null;
450
512
  this.provider = provider;
451
513
  this.walletId = walletId;
452
514
  this.walletName = walletName;
453
515
  this.setupEventListeners();
454
516
  }
455
- get connected() {
456
- return this._connected;
457
- }
458
517
  get publicKey() {
459
518
  return this._publicKey;
460
519
  }
520
+ get isConnected() {
521
+ return this.provider.isConnected || !!this._publicKey;
522
+ }
461
523
  async connect(options) {
462
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect", {
463
- walletId: this.walletId,
464
- walletName: this.walletName,
465
- onlyIfTrusted: options?.onlyIfTrusted
466
- });
467
524
  try {
468
- const result = await this.provider.connect(options);
469
- if (typeof result === "string") {
470
- this._connected = true;
471
- this._publicKey = result;
472
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
525
+ await this.provider.connect(options);
526
+ const isConnected = this.provider.isConnected;
527
+ if (!isConnected || this.provider.publicKey === null) {
528
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Provider not connected after connect() call", {
473
529
  walletId: this.walletId,
474
530
  walletName: this.walletName,
475
- publicKey: result
531
+ providerConnected: isConnected,
532
+ providerPublicKey: this.provider.publicKey
476
533
  });
477
- return { publicKey: result };
478
- }
479
- if (typeof result === "object" && result !== null && "publicKey" in result) {
480
- this._connected = true;
481
- this._publicKey = result.publicKey;
482
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
534
+ throw new Error("Provider not connected after connect() call");
535
+ }
536
+ let publicKey;
537
+ const providerPublicKey = this.provider.publicKey;
538
+ if (typeof providerPublicKey === "string") {
539
+ publicKey = providerPublicKey;
540
+ } else if (providerPublicKey !== null && providerPublicKey !== void 0 && typeof providerPublicKey.toString === "function") {
541
+ publicKey = providerPublicKey.toString();
542
+ } else {
543
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Invalid publicKey format in provider state", {
483
544
  walletId: this.walletId,
484
545
  walletName: this.walletName,
485
- publicKey: result.publicKey
546
+ publicKeyType: typeof providerPublicKey
486
547
  });
487
- return result;
488
- }
489
- if (Array.isArray(result) && result.length > 0) {
490
- const firstAccount = result[0];
491
- if (typeof firstAccount === "object" && firstAccount !== null && "address" in firstAccount) {
492
- this._connected = true;
493
- this._publicKey = firstAccount.address;
494
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
495
- walletId: this.walletId,
496
- walletName: this.walletName,
497
- publicKey: firstAccount.address
498
- });
499
- return { publicKey: firstAccount.address };
500
- }
548
+ throw new Error("Invalid publicKey format in provider state");
549
+ }
550
+ if (!publicKey || publicKey.length === 0) {
551
+ throw new Error("Empty publicKey from provider");
501
552
  }
502
- throw new Error("Unexpected connect result format");
553
+ this._publicKey = publicKey;
554
+ debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
555
+ walletId: this.walletId,
556
+ walletName: this.walletName,
557
+ publicKey
558
+ });
559
+ return { publicKey };
503
560
  } catch (error) {
504
561
  debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect failed", {
505
562
  walletId: this.walletId,
@@ -516,7 +573,6 @@ var InjectedWalletSolanaChain = class {
516
573
  });
517
574
  try {
518
575
  await this.provider.disconnect();
519
- this._connected = false;
520
576
  this._publicKey = null;
521
577
  debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnected", {
522
578
  walletId: this.walletId,
@@ -548,7 +604,7 @@ var InjectedWalletSolanaChain = class {
548
604
  signatureLength: result.signature.length
549
605
  });
550
606
  return {
551
- signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(Buffer2.from(result.signature, "base64")),
607
+ signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(Buffer.from(result.signature, "base64")),
552
608
  publicKey: result.publicKey || this._publicKey || ""
553
609
  };
554
610
  } catch (error) {
@@ -652,27 +708,19 @@ var InjectedWalletSolanaChain = class {
652
708
  switchNetwork(_network) {
653
709
  return Promise.resolve();
654
710
  }
655
- getPublicKey() {
656
- return Promise.resolve(this._publicKey);
657
- }
658
- isConnected() {
659
- return this._connected;
660
- }
661
711
  setupEventListeners() {
662
712
  if (typeof this.provider.on === "function") {
663
713
  this.provider.on("connect", (publicKey) => {
664
- this._connected = true;
665
714
  this._publicKey = publicKey;
666
715
  this.eventEmitter.emit("connect", publicKey);
667
716
  });
668
717
  this.provider.on("disconnect", () => {
669
- this._connected = false;
670
718
  this._publicKey = null;
671
719
  this.eventEmitter.emit("disconnect");
672
720
  });
673
721
  this.provider.on("accountChanged", (publicKey) => {
674
- this._publicKey = publicKey;
675
- this.eventEmitter.emit("accountChanged", publicKey);
722
+ this._publicKey = publicKey ? publicKey : null;
723
+ this.eventEmitter.emit("accountChanged", this._publicKey);
676
724
  });
677
725
  }
678
726
  }
@@ -685,26 +733,29 @@ var InjectedWalletSolanaChain = class {
685
733
  };
686
734
 
687
735
  // src/providers/injected/chains/WalletStandardSolanaAdapter.ts
736
+ import { EventEmitter as EventEmitter2 } from "eventemitter3";
688
737
  import { deserializeSolanaTransaction } from "@phantom/parsers";
738
+ import { Buffer as Buffer2 } from "buffer";
689
739
  import bs58 from "bs58";
690
740
  var WalletStandardSolanaAdapter = class {
691
741
  constructor(wallet, walletId, walletName) {
692
- this._connected = false;
742
+ this.eventEmitter = new EventEmitter2();
693
743
  this._publicKey = null;
694
744
  this.wallet = wallet;
695
745
  this.walletId = walletId;
696
746
  this.walletName = walletName;
697
- }
698
- get connected() {
699
- return this._connected;
747
+ this.setupEventListeners();
700
748
  }
701
749
  get publicKey() {
702
750
  return this._publicKey;
703
751
  }
752
+ get isConnected() {
753
+ return this._publicKey !== null;
754
+ }
704
755
  async connect(_options) {
705
756
  try {
706
- const connectFeature = this.wallet.features?.["standard:connect"];
707
- if (!connectFeature || typeof connectFeature.connect !== "function") {
757
+ const connectFeature = this.wallet.features["standard:connect"];
758
+ if (!connectFeature) {
708
759
  throw new Error("Wallet Standard connect feature not available");
709
760
  }
710
761
  const connectResult = await connectFeature.connect();
@@ -725,14 +776,13 @@ var WalletStandardSolanaAdapter = class {
725
776
  if (typeof firstAccount === "string") {
726
777
  address = firstAccount;
727
778
  } else if (typeof firstAccount === "object" && firstAccount !== null) {
728
- address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? Buffer.from(firstAccount.publicKey).toString("hex") : void 0);
779
+ address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? Buffer2.from(firstAccount.publicKey).toString("hex") : void 0);
729
780
  }
730
781
  if (!address) {
731
782
  throw new Error(
732
783
  `Could not extract address from account. Account structure: ${JSON.stringify(firstAccount, null, 2)}`
733
784
  );
734
785
  }
735
- this._connected = true;
736
786
  this._publicKey = address;
737
787
  return { publicKey: address };
738
788
  } catch (error) {
@@ -746,11 +796,10 @@ var WalletStandardSolanaAdapter = class {
746
796
  }
747
797
  async disconnect() {
748
798
  try {
749
- const disconnectFeature = this.wallet.features?.["standard:disconnect"];
750
- if (disconnectFeature && typeof disconnectFeature.disconnect === "function") {
799
+ const disconnectFeature = this.wallet.features["standard:disconnect"];
800
+ if (disconnectFeature) {
751
801
  await disconnectFeature.disconnect();
752
802
  }
753
- this._connected = false;
754
803
  this._publicKey = null;
755
804
  } catch (error) {
756
805
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana disconnect failed", {
@@ -763,14 +812,14 @@ var WalletStandardSolanaAdapter = class {
763
812
  }
764
813
  async signMessage(message) {
765
814
  try {
766
- const signMessageFeature = this.wallet.features?.["solana:signMessage"];
767
- if (!signMessageFeature || typeof signMessageFeature.signMessage !== "function") {
815
+ const signMessageFeature = this.wallet.features["solana:signMessage"];
816
+ if (!signMessageFeature) {
768
817
  throw new Error("Wallet Standard signMessage feature not available");
769
818
  }
770
819
  const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
771
820
  const result = await signMessageFeature.signMessage({
772
821
  message: messageBytes,
773
- account: this.wallet.accounts?.[0]
822
+ account: this.wallet.accounts[0]
774
823
  });
775
824
  if (!Array.isArray(result) || result.length === 0) {
776
825
  throw new Error(`Expected array result from signMessage, got: ${typeof result}`);
@@ -783,7 +832,7 @@ var WalletStandardSolanaAdapter = class {
783
832
  if (signature.length === 0) {
784
833
  throw new Error(`Signature is empty`);
785
834
  }
786
- const publicKey = signedMessageResult.account?.address || this.wallet.accounts?.[0]?.address || this._publicKey || "";
835
+ const publicKey = signedMessageResult.account?.address || this.wallet.accounts[0]?.address || this._publicKey || "";
787
836
  return { signature, publicKey };
788
837
  } catch (error) {
789
838
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signMessage failed", {
@@ -796,8 +845,8 @@ var WalletStandardSolanaAdapter = class {
796
845
  }
797
846
  async signTransaction(transaction) {
798
847
  try {
799
- const signTransactionFeature = this.wallet.features?.["solana:signTransaction"];
800
- if (!signTransactionFeature || typeof signTransactionFeature.signTransaction !== "function") {
848
+ const signTransactionFeature = this.wallet.features["solana:signTransaction"];
849
+ if (!signTransactionFeature) {
801
850
  throw new Error("Wallet Standard signTransaction feature not available");
802
851
  }
803
852
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -816,7 +865,8 @@ var WalletStandardSolanaAdapter = class {
816
865
  transactionData = firstItem.signedTransaction || firstItem.transaction;
817
866
  }
818
867
  } else if (results && typeof results === "object" && !Array.isArray(results)) {
819
- transactionData = results.transaction || results.signedTransaction;
868
+ const resultObj = results;
869
+ transactionData = resultObj.transaction || resultObj.signedTransaction;
820
870
  }
821
871
  if (!transactionData) {
822
872
  throw new Error("No transaction data found in Wallet Standard result");
@@ -838,8 +888,8 @@ var WalletStandardSolanaAdapter = class {
838
888
  }
839
889
  async signAndSendTransaction(transaction) {
840
890
  try {
841
- const signAndSendTransactionFeature = this.wallet.features?.["solana:signAndSendTransaction"];
842
- if (!signAndSendTransactionFeature || typeof signAndSendTransactionFeature.signAndSendTransaction !== "function") {
891
+ const signAndSendTransactionFeature = this.wallet.features["solana:signAndSendTransaction"];
892
+ if (!signAndSendTransactionFeature) {
843
893
  throw new Error("Wallet Standard signAndSendTransaction feature not available");
844
894
  }
845
895
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -910,40 +960,87 @@ var WalletStandardSolanaAdapter = class {
910
960
  throw error;
911
961
  }
912
962
  }
913
- async switchNetwork(network) {
914
- try {
915
- const switchNetworkFeature = this.wallet.features?.["standard:switchNetwork"];
916
- if (switchNetworkFeature && typeof switchNetworkFeature.switchNetwork === "function") {
917
- const chainId = network === "mainnet" ? "solana:mainnet" : "solana:devnet";
918
- await switchNetworkFeature.switchNetwork({ chain: chainId });
919
- }
920
- } catch (error) {
921
- debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana switchNetwork failed", {
963
+ async switchNetwork(_network) {
964
+ return Promise.resolve();
965
+ }
966
+ /**
967
+ * Set up event listeners for Wallet Standard events
968
+ * Maps Wallet Standard "change" events to "accountChanged" events
969
+ *
970
+ * Note: Wallet Standard only has a "change" event. There are no "connect" or "disconnect" events.
971
+ * Connection/disconnection is indicated by the presence or absence of accounts in the change event.
972
+ */
973
+ setupEventListeners() {
974
+ const eventsFeature = this.wallet.features["standard:events"];
975
+ if (!eventsFeature) {
976
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard events feature not available", {
922
977
  walletId: this.walletId,
923
- walletName: this.walletName,
924
- network,
925
- error: error instanceof Error ? error.message : String(error)
978
+ walletName: this.walletName
926
979
  });
927
- throw error;
980
+ return;
928
981
  }
982
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Wallet Standard event listeners", {
983
+ walletId: this.walletId,
984
+ walletName: this.walletName
985
+ });
986
+ eventsFeature.on("change", (properties) => {
987
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard change event received", {
988
+ walletId: this.walletId,
989
+ walletName: this.walletName,
990
+ hasAccounts: !!properties.accounts,
991
+ accountCount: properties.accounts?.length || 0
992
+ });
993
+ if (properties.accounts !== void 0) {
994
+ if (properties.accounts.length > 0) {
995
+ const firstAccount = properties.accounts[0];
996
+ const address = this.extractAccountAddress(firstAccount);
997
+ if (address) {
998
+ this._publicKey = address;
999
+ this.eventEmitter.emit("accountChanged", address);
1000
+ this.eventEmitter.emit("connect", address);
1001
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and connect events", {
1002
+ walletId: this.walletId,
1003
+ walletName: this.walletName,
1004
+ address
1005
+ });
1006
+ } else {
1007
+ this._publicKey = null;
1008
+ this.eventEmitter.emit("accountChanged", null);
1009
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged event (null - invalid account)", {
1010
+ walletId: this.walletId,
1011
+ walletName: this.walletName
1012
+ });
1013
+ }
1014
+ } else {
1015
+ this._publicKey = null;
1016
+ this.eventEmitter.emit("accountChanged", null);
1017
+ this.eventEmitter.emit("disconnect");
1018
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and disconnect events", {
1019
+ walletId: this.walletId,
1020
+ walletName: this.walletName
1021
+ });
1022
+ }
1023
+ }
1024
+ });
929
1025
  }
930
- getPublicKey() {
931
- return Promise.resolve(this._publicKey);
932
- }
933
- isConnected() {
934
- return this._connected;
1026
+ extractAccountAddress(account) {
1027
+ return account.address;
935
1028
  }
936
- on(_event, _listener) {
937
- const eventsFeature = this.wallet.features?.["standard:events"];
938
- if (eventsFeature && typeof eventsFeature.on === "function") {
939
- eventsFeature.on(_event, _listener);
940
- }
1029
+ on(event, listener) {
1030
+ this.eventEmitter.on(event, listener);
1031
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Added event listener", {
1032
+ walletId: this.walletId,
1033
+ walletName: this.walletName,
1034
+ event
1035
+ });
941
1036
  }
942
- off(_event, _listener) {
943
- const eventsFeature = this.wallet.features?.["standard:events"];
944
- if (eventsFeature && typeof eventsFeature.off === "function") {
945
- eventsFeature.off(_event, _listener);
946
- }
1037
+ off(event, listener) {
1038
+ this.eventEmitter.off(event, listener);
1039
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Removed event listener", {
1040
+ walletId: this.walletId,
1041
+ walletName: this.walletName,
1042
+ event
1043
+ });
947
1044
  }
948
1045
  /**
949
1046
  * Serialize a transaction to Uint8Array for Wallet Standard API
@@ -987,10 +1084,11 @@ var WalletStandardSolanaAdapter = class {
987
1084
  };
988
1085
 
989
1086
  // src/providers/injected/chains/InjectedWalletEthereumChain.ts
990
- import { EventEmitter as EventEmitter2 } from "eventemitter3";
1087
+ import { EventEmitter as EventEmitter3 } from "eventemitter3";
991
1088
  var InjectedWalletEthereumChain = class {
992
1089
  constructor(provider, walletId, walletName) {
993
- this.eventEmitter = new EventEmitter2();
1090
+ // Expose eventEmitter for testing - allows tests to trigger events directly
1091
+ this.eventEmitter = new EventEmitter3();
994
1092
  this._connected = false;
995
1093
  this._chainId = "0x1";
996
1094
  this._accounts = [];
@@ -999,9 +1097,6 @@ var InjectedWalletEthereumChain = class {
999
1097
  this.walletName = walletName;
1000
1098
  this.setupEventListeners();
1001
1099
  }
1002
- get connected() {
1003
- return this._connected;
1004
- }
1005
1100
  get chainId() {
1006
1101
  return this._chainId;
1007
1102
  }
@@ -1131,7 +1226,8 @@ var InjectedWalletEthereumChain = class {
1131
1226
  address
1132
1227
  });
1133
1228
  try {
1134
- const providerConnected = this.provider.isConnected?.() || this.provider.connected || false;
1229
+ const providerAny = this.provider;
1230
+ const providerConnected = (typeof providerAny.isConnected === "function" ? providerAny.isConnected() : false) || (typeof providerAny.connected === "boolean" ? providerAny.connected : false);
1135
1231
  if (!this._connected || this._accounts.length === 0 || !providerConnected) {
1136
1232
  debug.log(DebugCategory.INJECTED_PROVIDER, "Not connected, attempting to connect before signing", {
1137
1233
  walletId: this.walletId,
@@ -1364,6 +1460,7 @@ var InjectedWalletEthereumChain = class {
1364
1460
  });
1365
1461
  this.provider.on("accountsChanged", (accounts) => {
1366
1462
  this._accounts = accounts;
1463
+ this._connected = accounts.length > 0;
1367
1464
  this.eventEmitter.emit("accountsChanged", accounts);
1368
1465
  });
1369
1466
  this.provider.on("chainChanged", (chainId) => {
@@ -1380,218 +1477,13 @@ var InjectedWalletEthereumChain = class {
1380
1477
  }
1381
1478
  };
1382
1479
 
1383
- // src/providers/injected/chains/SolanaChain.ts
1384
- import { EventEmitter as EventEmitter3 } from "eventemitter3";
1385
- import { Buffer as Buffer3 } from "buffer";
1386
- var PhantomSolanaChain = class {
1387
- constructor(phantom) {
1388
- this._publicKey = null;
1389
- this.eventEmitter = new EventEmitter3();
1390
- this.phantom = phantom;
1391
- this.setupEventListeners();
1392
- }
1393
- // Wallet adapter compliant properties
1394
- get connected() {
1395
- return this._publicKey !== null;
1396
- }
1397
- get publicKey() {
1398
- return this._publicKey;
1399
- }
1400
- // Connection methods
1401
- async connect(options) {
1402
- const result = await this.phantom.solana.connect(options);
1403
- if (!result) {
1404
- throw new Error("Failed to connect to Solana wallet");
1405
- }
1406
- const publicKey = typeof result === "string" ? result : "";
1407
- this._publicKey = publicKey;
1408
- return { publicKey };
1409
- }
1410
- async disconnect() {
1411
- await this.phantom.solana.disconnect();
1412
- this._publicKey = null;
1413
- }
1414
- // Standard wallet adapter methods
1415
- async signMessage(message) {
1416
- const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
1417
- const result = await this.phantom.solana.signMessage(messageBytes);
1418
- return {
1419
- signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(Buffer3.from(result.signature, "base64")),
1420
- publicKey: this._publicKey || ""
1421
- };
1422
- }
1423
- async signTransaction(transaction) {
1424
- if (!this.connected) {
1425
- return Promise.reject(new Error("Provider not connected. Call provider connect first."));
1426
- }
1427
- try {
1428
- const result = await this.phantom.solana.signTransaction(transaction);
1429
- return result;
1430
- } catch (error) {
1431
- return Promise.reject(error);
1432
- }
1433
- }
1434
- async signAndSendTransaction(transaction) {
1435
- const result = await this.phantom.solana.signAndSendTransaction(transaction);
1436
- return { signature: result.signature };
1437
- }
1438
- async signAllTransactions(transactions) {
1439
- if (!this.connected) {
1440
- return Promise.reject(new Error("Provider not connected. Call provider connect first."));
1441
- }
1442
- try {
1443
- const result = await this.phantom.solana.signAllTransactions(transactions);
1444
- return result;
1445
- } catch (error) {
1446
- return Promise.reject(error);
1447
- }
1448
- }
1449
- async signAndSendAllTransactions(transactions) {
1450
- if (!this.connected) {
1451
- return Promise.reject(new Error("Provider not connected. Call provider connect first."));
1452
- }
1453
- try {
1454
- const result = await this.phantom.solana.signAndSendAllTransactions(transactions);
1455
- return { signatures: result.signatures };
1456
- } catch (error) {
1457
- return Promise.reject(error);
1458
- }
1459
- }
1460
- switchNetwork(_network) {
1461
- return Promise.resolve();
1462
- }
1463
- // Legacy methods
1464
- getPublicKey() {
1465
- return Promise.resolve(this._publicKey);
1466
- }
1467
- isConnected() {
1468
- return this.connected;
1469
- }
1470
- setupEventListeners() {
1471
- this.phantom.solana.addEventListener("connect", (publicKey) => {
1472
- this._publicKey = publicKey;
1473
- this.eventEmitter.emit("connect", publicKey);
1474
- });
1475
- this.phantom.solana.addEventListener("disconnect", () => {
1476
- this._publicKey = null;
1477
- this.eventEmitter.emit("disconnect");
1478
- });
1479
- this.phantom.solana.addEventListener("accountChanged", (publicKey) => {
1480
- this._publicKey = publicKey;
1481
- this.eventEmitter.emit("accountChanged", publicKey);
1482
- });
1483
- }
1484
- // Event methods for interface compliance
1485
- on(event, listener) {
1486
- this.eventEmitter.on(event, listener);
1487
- }
1488
- off(event, listener) {
1489
- this.eventEmitter.off(event, listener);
1490
- }
1491
- };
1492
-
1493
- // src/providers/injected/chains/EthereumChain.ts
1494
- import { EventEmitter as EventEmitter4 } from "eventemitter3";
1495
- var PhantomEthereumChain = class {
1496
- constructor(phantom) {
1497
- this._chainId = "0x1";
1498
- this._accounts = [];
1499
- this.eventEmitter = new EventEmitter4();
1500
- this.phantom = phantom;
1501
- this.setupEventListeners();
1502
- }
1503
- // EIP-1193 compliant properties
1504
- get connected() {
1505
- return this._accounts.length > 0;
1506
- }
1507
- get chainId() {
1508
- return this._chainId;
1509
- }
1510
- get accounts() {
1511
- return this._accounts;
1512
- }
1513
- // EIP-1193 core method with eth_signTransaction support
1514
- async request(args) {
1515
- if (args.method === "eth_signTransaction") {
1516
- const [transaction] = args.params;
1517
- const result = await this.signTransaction(transaction);
1518
- return result;
1519
- }
1520
- const phantomProvider = await this.phantom.ethereum.getProvider();
1521
- return await phantomProvider.request(args);
1522
- }
1523
- // Connection methods
1524
- async connect() {
1525
- const accounts = await this.phantom.ethereum.getAccounts();
1526
- this._accounts = accounts;
1527
- return accounts;
1528
- }
1529
- async disconnect() {
1530
- await this.phantom.ethereum.disconnect();
1531
- this._accounts = [];
1532
- }
1533
- // Standard compliant methods (return raw values, not wrapped objects)
1534
- async signPersonalMessage(message, address) {
1535
- return await this.phantom.ethereum.signPersonalMessage(message, address);
1536
- }
1537
- async signTypedData(typedData, address) {
1538
- return await this.phantom.ethereum.signTypedData(typedData, address);
1539
- }
1540
- async signTransaction(transaction) {
1541
- return await this.phantom.ethereum.signTransaction(transaction);
1542
- }
1543
- async sendTransaction(transaction) {
1544
- return await this.phantom.ethereum.sendTransaction(transaction);
1545
- }
1546
- async switchChain(chainId) {
1547
- const hexChainId = typeof chainId === "string" ? chainId.toLowerCase().startsWith("0x") ? chainId : `0x${parseInt(chainId, 10).toString(16)}` : `0x${chainId.toString(16)}`;
1548
- await this.phantom.ethereum.switchChain(hexChainId);
1549
- this._chainId = hexChainId;
1550
- this.eventEmitter.emit("chainChanged", this._chainId);
1551
- }
1552
- async getChainId() {
1553
- const chainId = await this.phantom.ethereum.getChainId();
1554
- return parseInt(chainId, 16);
1555
- }
1556
- async getAccounts() {
1557
- return await this.phantom.ethereum.getAccounts();
1558
- }
1559
- isConnected() {
1560
- return this.connected;
1561
- }
1562
- setupEventListeners() {
1563
- this.phantom.ethereum.addEventListener("connect", (accounts) => {
1564
- this._accounts = accounts;
1565
- this.eventEmitter.emit("connect", { chainId: this._chainId });
1566
- this.eventEmitter.emit("accountsChanged", accounts);
1567
- });
1568
- this.phantom.ethereum.addEventListener("disconnect", () => {
1569
- this._accounts = [];
1570
- this.eventEmitter.emit("disconnect", { code: 4900, message: "Provider disconnected" });
1571
- this.eventEmitter.emit("accountsChanged", []);
1572
- });
1573
- this.phantom.ethereum.addEventListener("accountsChanged", (accounts) => {
1574
- this._accounts = accounts;
1575
- this.eventEmitter.emit("accountsChanged", accounts);
1576
- });
1577
- this.phantom.ethereum.addEventListener("chainChanged", (chainId) => {
1578
- this._chainId = chainId;
1579
- this.eventEmitter.emit("chainChanged", chainId);
1580
- });
1581
- }
1582
- // Event methods for interface compliance
1583
- on(event, listener) {
1584
- this.eventEmitter.on(event, listener);
1585
- }
1586
- off(event, listener) {
1587
- this.eventEmitter.off(event, listener);
1588
- }
1589
- };
1590
-
1591
1480
  // src/wallets/registry.ts
1592
1481
  function isPhantomWallet(wallet) {
1593
1482
  return wallet !== void 0 && wallet.id === "phantom" && "isPhantom" in wallet && wallet.isPhantom === true;
1594
1483
  }
1484
+ function isWalletStandardWallet(provider) {
1485
+ return provider !== null && typeof provider === "object" && "features" in provider && typeof provider.features === "object";
1486
+ }
1595
1487
  var InjectedWalletRegistry = class {
1596
1488
  constructor() {
1597
1489
  this.wallets = /* @__PURE__ */ new Map();
@@ -1600,8 +1492,7 @@ var InjectedWalletRegistry = class {
1600
1492
  register(info) {
1601
1493
  const wrappedProviders = {};
1602
1494
  if (info.providers?.solana) {
1603
- const isWalletStandard = info.providers.solana && typeof info.providers.solana === "object" && "features" in info.providers.solana && typeof info.providers.solana.features === "object";
1604
- if (isWalletStandard) {
1495
+ if (isWalletStandardWallet(info.providers.solana)) {
1605
1496
  wrappedProviders.solana = new WalletStandardSolanaAdapter(info.providers.solana, info.id, info.name);
1606
1497
  debug.log(DebugCategory.BROWSER_SDK, "Wrapped Wallet Standard Solana wallet with adapter", {
1607
1498
  walletId: info.id,
@@ -1631,26 +1522,26 @@ var InjectedWalletRegistry = class {
1631
1522
  /**
1632
1523
  * Register Phantom wallet with its instance
1633
1524
  * This creates wrapped providers and stores the Phantom instance for auto-confirm access
1525
+ * Uses unified InjectedWallet chains for both Phantom and external wallets
1634
1526
  */
1635
1527
  registerPhantom(phantomInstance, addressTypes) {
1636
1528
  const wrappedProviders = {};
1637
1529
  if (addressTypes.includes(AddressType.solana) && phantomInstance.solana) {
1638
- wrappedProviders.solana = new PhantomSolanaChain(phantomInstance);
1639
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomSolanaChain wrapper", {
1530
+ wrappedProviders.solana = new InjectedWalletSolanaChain(phantomInstance.solana, "phantom", "Phantom");
1531
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletSolanaChain wrapper for Phantom", {
1640
1532
  walletId: "phantom"
1641
1533
  });
1642
1534
  }
1643
1535
  if (addressTypes.includes(AddressType.ethereum) && phantomInstance.ethereum) {
1644
- wrappedProviders.ethereum = new PhantomEthereumChain(phantomInstance);
1645
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomEthereumChain wrapper", {
1536
+ wrappedProviders.ethereum = new InjectedWalletEthereumChain(phantomInstance.ethereum, "phantom", "Phantom");
1537
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletEthereumChain wrapper for Phantom", {
1646
1538
  walletId: "phantom"
1647
1539
  });
1648
1540
  }
1649
1541
  const phantomWallet = {
1650
1542
  id: "phantom",
1651
1543
  name: "Phantom",
1652
- icon: "",
1653
- // Icon will be rendered from icons package in UI components
1544
+ icon: PHANTOM_ICON2,
1654
1545
  addressTypes,
1655
1546
  providers: wrappedProviders,
1656
1547
  isPhantom: true,
@@ -1727,15 +1618,16 @@ var WAS_CONNECTED_KEY = "phantom-injected-was-connected";
1727
1618
  var WAS_CONNECTED_VALUE = "true";
1728
1619
  var LAST_WALLET_ID_KEY = "phantom-injected-last-wallet-id";
1729
1620
  var InjectedProvider = class {
1730
- // Track which wallets have event listeners set up
1621
+ // Store cleanups per walletId
1731
1622
  constructor(config) {
1732
1623
  this.selectedWalletId = null;
1733
1624
  this.walletStates = /* @__PURE__ */ new Map();
1734
1625
  // Event management
1735
1626
  this.eventListeners = /* @__PURE__ */ new Map();
1736
- this.browserInjectedCleanupFunctions = [];
1737
1627
  this.eventsInitialized = false;
1738
- this.externalWalletEventListenersSetup = /* @__PURE__ */ new Set();
1628
+ this.eventListenersSetup = /* @__PURE__ */ new Set();
1629
+ // Track walletId that have listeners set up
1630
+ this.eventListenerCleanups = /* @__PURE__ */ new Map();
1739
1631
  debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
1740
1632
  this.addressTypes = config.addressTypes;
1741
1633
  this.walletRegistry = getWalletRegistry();
@@ -1766,9 +1658,12 @@ var InjectedProvider = class {
1766
1658
  });
1767
1659
  }
1768
1660
  }
1769
- get solana() {
1770
- if (!this.addressTypes.includes(AddressType2.solana)) {
1771
- throw new Error("Solana not enabled for this provider");
1661
+ /**
1662
+ * Helper method to get a chain provider with consistent error handling
1663
+ */
1664
+ getChainProvider(addressType, providerKey, chainName) {
1665
+ if (!this.addressTypes.includes(addressType)) {
1666
+ throw new Error(`${chainName} not enabled for this provider`);
1772
1667
  }
1773
1668
  const walletId = this.selectedWalletId || "phantom";
1774
1669
  const walletInfo = this.walletRegistry.getById(walletId);
@@ -1783,46 +1678,29 @@ var InjectedProvider = class {
1783
1678
  `Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
1784
1679
  );
1785
1680
  }
1786
- if (!walletInfo.providers?.solana) {
1681
+ const provider = walletInfo.providers?.[providerKey];
1682
+ if (!provider) {
1787
1683
  throw new Error(
1788
- `Selected wallet "${walletInfo.name}" does not support Solana. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Solana in addressTypes.`
1684
+ `Selected wallet "${walletInfo.name}" does not support ${chainName}. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes ${chainName} in addressTypes.`
1789
1685
  );
1790
1686
  }
1791
- return walletInfo.providers.solana;
1687
+ return provider;
1688
+ }
1689
+ get solana() {
1690
+ return this.getChainProvider(AddressType3.solana, "solana", "Solana");
1792
1691
  }
1793
1692
  /**
1794
1693
  * Access to Ethereum chain operations
1795
1694
  */
1796
1695
  get ethereum() {
1797
- if (!this.addressTypes.includes(AddressType2.ethereum)) {
1798
- throw new Error("Ethereum not enabled for this provider");
1799
- }
1800
- const walletId = this.selectedWalletId || "phantom";
1801
- const walletInfo = this.walletRegistry.getById(walletId);
1802
- if (!walletInfo) {
1803
- const registry = this.walletRegistry;
1804
- if (registry.discoveryPromise) {
1805
- throw new Error(
1806
- `Wallet "${walletId}" not found. Wallet discovery is still in progress. Please wait for sdk.discoverWallets() to complete before accessing chain properties.`
1807
- );
1808
- }
1809
- throw new Error(
1810
- `Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
1811
- );
1812
- }
1813
- if (!walletInfo.providers?.ethereum) {
1814
- throw new Error(
1815
- `Selected wallet "${walletInfo.name}" does not support Ethereum. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Ethereum in addressTypes.`
1816
- );
1817
- }
1818
- return walletInfo.providers.ethereum;
1819
- }
1820
- validateAndSelectWallet(requestedWalletId) {
1821
- if (!this.walletRegistry.has(requestedWalletId)) {
1822
- debug.error(DebugCategory.INJECTED_PROVIDER, "Unknown injected wallet id requested", {
1823
- walletId: requestedWalletId
1824
- });
1825
- throw new Error(`Unknown injected wallet id: ${requestedWalletId}`);
1696
+ return this.getChainProvider(AddressType3.ethereum, "ethereum", "Ethereum");
1697
+ }
1698
+ validateAndSelectWallet(requestedWalletId) {
1699
+ if (!this.walletRegistry.has(requestedWalletId)) {
1700
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Unknown injected wallet id requested", {
1701
+ walletId: requestedWalletId
1702
+ });
1703
+ throw new Error(`Unknown injected wallet id: ${requestedWalletId}`);
1826
1704
  }
1827
1705
  const walletInfo = this.walletRegistry.getById(requestedWalletId);
1828
1706
  if (!walletInfo || !walletInfo.providers) {
@@ -1853,16 +1731,10 @@ var InjectedProvider = class {
1853
1731
  options
1854
1732
  });
1855
1733
  if (!options?.skipEventListeners) {
1856
- this.setupExternalWalletEvents(walletInfo);
1857
- if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
1858
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
1859
- this.browserInjectedCleanupFunctions = [];
1860
- this.setupBrowserInjectedEvents();
1861
- this.eventsInitialized = true;
1862
- }
1734
+ this.setupEventListeners(walletInfo);
1863
1735
  }
1864
1736
  const connectedAddresses = [];
1865
- if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers?.solana) {
1737
+ if (this.addressTypes.includes(AddressType3.solana) && walletInfo.providers?.solana) {
1866
1738
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection", {
1867
1739
  walletId: this.selectedWalletId,
1868
1740
  walletName: walletInfo.name,
@@ -1874,7 +1746,7 @@ var InjectedProvider = class {
1874
1746
  );
1875
1747
  const address = result.publicKey;
1876
1748
  connectedAddresses.push({
1877
- addressType: AddressType2.solana,
1749
+ addressType: AddressType3.solana,
1878
1750
  address
1879
1751
  });
1880
1752
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", {
@@ -1895,7 +1767,7 @@ var InjectedProvider = class {
1895
1767
  throw err;
1896
1768
  }
1897
1769
  }
1898
- if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers?.ethereum) {
1770
+ if (this.addressTypes.includes(AddressType3.ethereum) && walletInfo.providers?.ethereum) {
1899
1771
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum connection", {
1900
1772
  walletId: this.selectedWalletId,
1901
1773
  walletName: walletInfo.name,
@@ -1911,7 +1783,7 @@ var InjectedProvider = class {
1911
1783
  if (accounts.length > 0) {
1912
1784
  connectedAddresses.push(
1913
1785
  ...accounts.map((address) => ({
1914
- addressType: AddressType2.ethereum,
1786
+ addressType: AddressType3.ethereum,
1915
1787
  address
1916
1788
  }))
1917
1789
  );
@@ -1991,7 +1863,8 @@ var InjectedProvider = class {
1991
1863
  this.emit("connect", {
1992
1864
  addresses: connectedAddresses,
1993
1865
  source: "manual-connect",
1994
- authUserId
1866
+ authUserId,
1867
+ walletId
1995
1868
  });
1996
1869
  return result;
1997
1870
  }
@@ -2003,12 +1876,13 @@ var InjectedProvider = class {
2003
1876
  if (authOptions.provider !== "injected") {
2004
1877
  throw new Error(`Invalid provider for injected connection: ${authOptions.provider}. Must be "injected"`);
2005
1878
  }
1879
+ const requestedWalletId = authOptions.walletId || "phantom";
2006
1880
  this.emit("connect_start", {
2007
1881
  source: "manual-connect",
2008
- providerType: "injected"
1882
+ providerType: "injected",
1883
+ walletId: requestedWalletId
2009
1884
  });
2010
1885
  try {
2011
- const requestedWalletId = authOptions.walletId || "phantom";
2012
1886
  const walletInfo = this.validateAndSelectWallet(requestedWalletId);
2013
1887
  const connectedAddresses = await this.connectToWallet(walletInfo);
2014
1888
  return await this.finalizeConnection(connectedAddresses, "injected", this.selectedWalletId || void 0);
@@ -2024,7 +1898,7 @@ var InjectedProvider = class {
2024
1898
  debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
2025
1899
  const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
2026
1900
  if (walletInfo?.providers) {
2027
- if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers.solana) {
1901
+ if (this.addressTypes.includes(AddressType3.solana) && walletInfo.providers.solana) {
2028
1902
  try {
2029
1903
  await walletInfo.providers.solana.disconnect();
2030
1904
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
@@ -2032,7 +1906,7 @@ var InjectedProvider = class {
2032
1906
  debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
2033
1907
  }
2034
1908
  }
2035
- if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers.ethereum) {
1909
+ if (this.addressTypes.includes(AddressType3.ethereum) && walletInfo.providers.ethereum) {
2036
1910
  try {
2037
1911
  await walletInfo.providers.ethereum.disconnect();
2038
1912
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
@@ -2041,10 +1915,14 @@ var InjectedProvider = class {
2041
1915
  }
2042
1916
  }
2043
1917
  }
2044
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
2045
- this.browserInjectedCleanupFunctions = [];
1918
+ const walletId = this.selectedWalletId || "phantom";
1919
+ const cleanups = this.eventListenerCleanups.get(walletId);
1920
+ if (cleanups) {
1921
+ cleanups.forEach((cleanup) => cleanup());
1922
+ this.eventListenerCleanups.delete(walletId);
1923
+ }
1924
+ this.eventListenersSetup.delete(walletId);
2046
1925
  if (this.selectedWalletId) {
2047
- this.externalWalletEventListenersSetup.delete(this.selectedWalletId);
2048
1926
  this.setWalletState(this.selectedWalletId, {
2049
1927
  connected: false,
2050
1928
  addresses: []
@@ -2113,13 +1991,7 @@ var InjectedProvider = class {
2113
1991
  });
2114
1992
  return;
2115
1993
  }
2116
- this.setupExternalWalletEvents(walletInfo);
2117
- if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
2118
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
2119
- this.browserInjectedCleanupFunctions = [];
2120
- this.setupBrowserInjectedEvents();
2121
- this.eventsInitialized = true;
2122
- }
1994
+ this.setupEventListeners(walletInfo);
2123
1995
  if (this.selectedWalletId) {
2124
1996
  this.setWalletState(this.selectedWalletId, {
2125
1997
  connected: true,
@@ -2130,7 +2002,8 @@ var InjectedProvider = class {
2130
2002
  this.emit("connect", {
2131
2003
  addresses: connectedAddresses,
2132
2004
  source: "auto-connect",
2133
- authUserId
2005
+ authUserId,
2006
+ walletId: this.selectedWalletId
2134
2007
  });
2135
2008
  debug.info(DebugCategory.INJECTED_PROVIDER, "Auto-connect successful", {
2136
2009
  addressCount: connectedAddresses.length,
@@ -2160,6 +2033,170 @@ var InjectedProvider = class {
2160
2033
  setWalletState(walletId, state) {
2161
2034
  this.walletStates.set(walletId, state);
2162
2035
  }
2036
+ /**
2037
+ * Update wallet state with new addresses for a specific address type
2038
+ * Replaces all existing addresses of the given type with the new addresses
2039
+ * @param walletId - The wallet ID to update
2040
+ * @param newAddresses - Array of new addresses (strings) for the address type
2041
+ * @param addressType - The type of addresses being updated
2042
+ * @returns The updated addresses array
2043
+ */
2044
+ updateWalletAddresses(walletId, newAddresses, addressType) {
2045
+ const state = this.getWalletState(walletId);
2046
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== addressType);
2047
+ const addressesOfType = newAddresses.map((address) => ({ addressType, address }));
2048
+ const updatedAddresses = [...otherAddresses, ...addressesOfType];
2049
+ this.setWalletState(walletId, {
2050
+ connected: updatedAddresses.length > 0,
2051
+ addresses: updatedAddresses
2052
+ });
2053
+ return updatedAddresses;
2054
+ }
2055
+ /**
2056
+ * Helper to construct account change source string
2057
+ */
2058
+ getAccountChangeSource(source) {
2059
+ return `${source}-account-change`;
2060
+ }
2061
+ /**
2062
+ * Create a handler for Solana connect events
2063
+ */
2064
+ createSolanaConnectHandler(walletId, source) {
2065
+ return async (publicKey) => {
2066
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey, walletId });
2067
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType3.solana);
2068
+ const authUserId = await this.getAuthUserId("Solana connect event");
2069
+ this.emit("connect", {
2070
+ addresses: newAddresses,
2071
+ source,
2072
+ authUserId,
2073
+ walletId: this.selectedWalletId
2074
+ });
2075
+ };
2076
+ }
2077
+ /**
2078
+ * Create a handler for Solana disconnect events
2079
+ */
2080
+ createSolanaDisconnectHandler(walletId, source) {
2081
+ return () => {
2082
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received", { walletId });
2083
+ const state = this.getWalletState(walletId);
2084
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.solana);
2085
+ this.setWalletState(walletId, {
2086
+ connected: filteredAddresses.length > 0,
2087
+ addresses: filteredAddresses
2088
+ });
2089
+ this.emit("disconnect", {
2090
+ source
2091
+ });
2092
+ };
2093
+ }
2094
+ /**
2095
+ * Create a handler for Solana account change events
2096
+ * Can receive string | null per Wallet Standard
2097
+ */
2098
+ createSolanaAccountChangeHandler(walletId, source) {
2099
+ return async (publicKey) => {
2100
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey, walletId });
2101
+ if (publicKey) {
2102
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType3.solana);
2103
+ const authUserId = await this.getAuthUserId("Solana account changed event");
2104
+ this.emit("connect", {
2105
+ addresses: newAddresses,
2106
+ source: this.getAccountChangeSource(source),
2107
+ authUserId,
2108
+ walletId: this.selectedWalletId
2109
+ });
2110
+ } else {
2111
+ const state = this.getWalletState(walletId);
2112
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.solana);
2113
+ this.setWalletState(walletId, {
2114
+ connected: otherAddresses.length > 0,
2115
+ addresses: otherAddresses
2116
+ });
2117
+ this.emit("disconnect", {
2118
+ source: this.getAccountChangeSource(source)
2119
+ });
2120
+ }
2121
+ };
2122
+ }
2123
+ /**
2124
+ * Create a handler for Ethereum connect events
2125
+ * EIP-1193 connect event receives { chainId: string }, but we need to get accounts separately
2126
+ */
2127
+ createEthereumConnectHandler(walletId, source) {
2128
+ return async (connectInfo) => {
2129
+ let accounts = [];
2130
+ if (Array.isArray(connectInfo)) {
2131
+ accounts = connectInfo;
2132
+ } else {
2133
+ try {
2134
+ const walletInfo = this.walletRegistry.getById(walletId);
2135
+ if (walletInfo?.providers?.ethereum) {
2136
+ accounts = await walletInfo.providers.ethereum.getAccounts();
2137
+ }
2138
+ } catch (error) {
2139
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to get accounts on connect", { error });
2140
+ }
2141
+ }
2142
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts, walletId });
2143
+ if (accounts.length > 0) {
2144
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType3.ethereum);
2145
+ const authUserId = await this.getAuthUserId("Ethereum connect event");
2146
+ this.emit("connect", {
2147
+ addresses: newAddresses,
2148
+ source,
2149
+ authUserId,
2150
+ walletId: this.selectedWalletId
2151
+ });
2152
+ }
2153
+ };
2154
+ }
2155
+ /**
2156
+ * Create a handler for Ethereum disconnect events
2157
+ */
2158
+ createEthereumDisconnectHandler(walletId, source) {
2159
+ return () => {
2160
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received", { walletId });
2161
+ const state = this.getWalletState(walletId);
2162
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.ethereum);
2163
+ this.setWalletState(walletId, {
2164
+ connected: filteredAddresses.length > 0,
2165
+ addresses: filteredAddresses
2166
+ });
2167
+ this.emit("disconnect", {
2168
+ source
2169
+ });
2170
+ };
2171
+ }
2172
+ /**
2173
+ * Create a handler for Ethereum account change events
2174
+ */
2175
+ createEthereumAccountChangeHandler(walletId, source) {
2176
+ return async (accounts) => {
2177
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts, walletId });
2178
+ if (accounts && accounts.length > 0) {
2179
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType3.ethereum);
2180
+ const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2181
+ this.emit("connect", {
2182
+ addresses: newAddresses,
2183
+ source: this.getAccountChangeSource(source),
2184
+ authUserId,
2185
+ walletId: this.selectedWalletId
2186
+ });
2187
+ } else {
2188
+ const state = this.getWalletState(walletId);
2189
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.ethereum);
2190
+ this.setWalletState(walletId, {
2191
+ connected: otherAddresses.length > 0,
2192
+ addresses: otherAddresses
2193
+ });
2194
+ this.emit("disconnect", {
2195
+ source: this.getAccountChangeSource(source)
2196
+ });
2197
+ }
2198
+ };
2199
+ }
2163
2200
  getAddresses() {
2164
2201
  const walletId = this.selectedWalletId || "phantom";
2165
2202
  return this.getWalletState(walletId).addresses;
@@ -2253,19 +2290,22 @@ var InjectedProvider = class {
2253
2290
  on(event, callback) {
2254
2291
  debug.log(DebugCategory.INJECTED_PROVIDER, "Adding event listener", { event });
2255
2292
  if (!this.eventsInitialized) {
2256
- this.setupBrowserInjectedEvents();
2257
- this.eventsInitialized = true;
2293
+ const walletId = this.selectedWalletId || "phantom";
2294
+ const walletInfo = this.walletRegistry.getById(walletId);
2295
+ if (walletInfo) {
2296
+ this.setupEventListeners(walletInfo);
2297
+ }
2258
2298
  }
2259
2299
  if (!this.eventListeners.has(event)) {
2260
2300
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
2261
2301
  }
2262
- this.eventListeners.get(event).add(callback);
2302
+ this.eventListeners.get(event)?.add(callback);
2263
2303
  }
2264
2304
  off(event, callback) {
2265
2305
  debug.log(DebugCategory.INJECTED_PROVIDER, "Removing event listener", { event });
2266
2306
  if (this.eventListeners.has(event)) {
2267
- this.eventListeners.get(event).delete(callback);
2268
- if (this.eventListeners.get(event).size === 0) {
2307
+ this.eventListeners.get(event)?.delete(callback);
2308
+ if (this.eventListeners.get(event)?.size === 0) {
2269
2309
  this.eventListeners.delete(event);
2270
2310
  }
2271
2311
  }
@@ -2287,246 +2327,89 @@ var InjectedProvider = class {
2287
2327
  });
2288
2328
  }
2289
2329
  }
2290
- setupBrowserInjectedEvents() {
2291
- const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
2292
- if (!isPhantomWallet(walletInfo)) {
2293
- debug.log(DebugCategory.INJECTED_PROVIDER, "Skipping browser-injected-sdk event setup - not Phantom wallet");
2330
+ /**
2331
+ * Set up Solana event listeners for any provider (Phantom or external)
2332
+ */
2333
+ setupSolanaEventListeners(provider, walletId, source) {
2334
+ if (typeof provider.on !== "function")
2294
2335
  return;
2295
- }
2296
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
2297
- if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
2298
- if (this.addressTypes.includes(AddressType2.solana)) {
2299
- this.setupSolanaEvents(walletInfo.phantomInstance);
2300
- }
2301
- if (this.addressTypes.includes(AddressType2.ethereum)) {
2302
- this.setupEthereumEvents(walletInfo.phantomInstance);
2303
- }
2304
- }
2305
- }
2306
- setupSolanaEvents(phantom) {
2307
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
2308
- const handleSolanaConnect = async (publicKey) => {
2309
- debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
2310
- const walletId = this.selectedWalletId || "phantom";
2311
- const state = this.getWalletState(walletId);
2312
- const solanaAddress = { addressType: AddressType2.solana, address: publicKey };
2313
- const hasSolana = state.addresses.some((addr) => addr.addressType === AddressType2.solana);
2314
- const newAddresses = hasSolana ? state.addresses.map((addr) => addr.addressType === AddressType2.solana ? solanaAddress : addr) : [...state.addresses, solanaAddress];
2315
- this.setWalletState(walletId, {
2316
- connected: true,
2317
- addresses: newAddresses
2318
- });
2319
- const authUserId = await this.getAuthUserId("Solana connect event");
2320
- this.emit("connect", {
2321
- addresses: newAddresses,
2322
- source: "injected-extension",
2323
- authUserId
2324
- });
2325
- };
2326
- const handleSolanaDisconnect = () => {
2327
- debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
2328
- const walletId = this.selectedWalletId || "phantom";
2329
- const state = this.getWalletState(walletId);
2330
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
2331
- this.setWalletState(walletId, {
2332
- connected: filteredAddresses.length > 0,
2333
- addresses: filteredAddresses
2334
- });
2335
- this.emit("disconnect", {
2336
- source: "injected-extension"
2337
- });
2336
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners", { walletId, source });
2337
+ const handlers = {
2338
+ connect: this.createSolanaConnectHandler(walletId, source),
2339
+ disconnect: this.createSolanaDisconnectHandler(walletId, source),
2340
+ accountChanged: this.createSolanaAccountChangeHandler(walletId, source)
2338
2341
  };
2339
- const handleSolanaAccountChanged = async (publicKey) => {
2340
- debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
2341
- const walletId = this.selectedWalletId || "phantom";
2342
- const state = this.getWalletState(walletId);
2343
- const solanaIndex = state.addresses.findIndex((addr) => addr.addressType === AddressType2.solana);
2344
- const newAddresses = solanaIndex >= 0 ? state.addresses.map(
2345
- (addr, idx) => idx === solanaIndex ? { addressType: AddressType2.solana, address: publicKey } : addr
2346
- ) : [...state.addresses, { addressType: AddressType2.solana, address: publicKey }];
2347
- this.setWalletState(walletId, {
2348
- connected: true,
2349
- addresses: newAddresses
2350
- });
2351
- const authUserId = await this.getAuthUserId("Solana account changed event");
2352
- this.emit("connect", {
2353
- addresses: newAddresses,
2354
- source: "injected-extension-account-change",
2355
- authUserId
2356
- });
2357
- };
2358
- const cleanupConnect = phantom.solana.addEventListener("connect", handleSolanaConnect);
2359
- const cleanupDisconnect = phantom.solana.addEventListener("disconnect", handleSolanaDisconnect);
2360
- const cleanupAccountChanged = phantom.solana.addEventListener("accountChanged", handleSolanaAccountChanged);
2361
- this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountChanged);
2362
- }
2363
- setupEthereumEvents(phantom) {
2364
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
2365
- const handleEthereumConnect = async (accounts) => {
2366
- debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
2367
- const walletId = this.selectedWalletId || "phantom";
2368
- const state = this.getWalletState(walletId);
2369
- const ethAddresses = accounts.map((address) => ({ addressType: AddressType2.ethereum, address }));
2370
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2371
- const newAddresses = [...otherAddresses, ...ethAddresses];
2372
- this.setWalletState(walletId, {
2373
- connected: true,
2374
- addresses: newAddresses
2375
- });
2376
- const authUserId = await this.getAuthUserId("Ethereum connect event");
2377
- this.emit("connect", {
2378
- addresses: newAddresses,
2379
- source: "injected-extension",
2380
- authUserId
2381
- });
2382
- };
2383
- const handleEthereumDisconnect = () => {
2384
- debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
2385
- const walletId = this.selectedWalletId || "phantom";
2386
- const state = this.getWalletState(walletId);
2387
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2388
- this.setWalletState(walletId, {
2389
- connected: filteredAddresses.length > 0,
2390
- addresses: filteredAddresses
2391
- });
2392
- this.emit("disconnect", {
2393
- source: "injected-extension"
2394
- });
2395
- };
2396
- const handleEthereumAccountsChanged = async (accounts) => {
2397
- debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts });
2398
- const walletId = this.selectedWalletId || "phantom";
2399
- const state = this.getWalletState(walletId);
2400
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2401
- if (accounts && accounts.length > 0) {
2402
- const ethAddresses = accounts.map((address) => ({ addressType: AddressType2.ethereum, address }));
2403
- const newAddresses = [...otherAddresses, ...ethAddresses];
2404
- this.setWalletState(walletId, {
2405
- connected: true,
2406
- addresses: newAddresses
2407
- });
2408
- const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2409
- this.emit("connect", {
2410
- addresses: newAddresses,
2411
- source: "injected-extension-account-change",
2412
- authUserId
2413
- });
2414
- } else {
2415
- this.setWalletState(walletId, {
2416
- connected: otherAddresses.length > 0,
2417
- addresses: otherAddresses
2418
- });
2419
- this.emit("disconnect", {
2420
- source: "injected-extension-account-change"
2421
- });
2422
- }
2423
- };
2424
- const cleanupConnect = phantom.ethereum.addEventListener("connect", handleEthereumConnect);
2425
- const cleanupDisconnect = phantom.ethereum.addEventListener("disconnect", handleEthereumDisconnect);
2426
- const cleanupAccountsChanged = phantom.ethereum.addEventListener("accountsChanged", handleEthereumAccountsChanged);
2427
- this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountsChanged);
2342
+ provider.on("connect", handlers.connect);
2343
+ provider.on("disconnect", handlers.disconnect);
2344
+ provider.on("accountChanged", handlers.accountChanged);
2345
+ const cleanups = [];
2346
+ if (typeof provider.off === "function") {
2347
+ cleanups.push(
2348
+ () => provider.off("connect", handlers.connect),
2349
+ () => provider.off("disconnect", handlers.disconnect),
2350
+ () => provider.off("accountChanged", handlers.accountChanged)
2351
+ );
2352
+ }
2353
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2354
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2428
2355
  }
2429
- setupExternalWalletEvents(walletInfo) {
2430
- if (isPhantomWallet(walletInfo)) {
2356
+ /**
2357
+ * Set up Ethereum event listeners for any provider (Phantom or external)
2358
+ */
2359
+ setupEthereumEventListeners(provider, walletId, source) {
2360
+ if (typeof provider.on !== "function")
2431
2361
  return;
2362
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners", { walletId, source });
2363
+ const handlers = {
2364
+ connect: this.createEthereumConnectHandler(walletId, source),
2365
+ disconnect: this.createEthereumDisconnectHandler(walletId, source),
2366
+ accountsChanged: this.createEthereumAccountChangeHandler(walletId, source)
2367
+ };
2368
+ provider.on("connect", handlers.connect);
2369
+ provider.on("disconnect", handlers.disconnect);
2370
+ provider.on("accountsChanged", handlers.accountsChanged);
2371
+ const cleanups = [];
2372
+ if (typeof provider.off === "function") {
2373
+ cleanups.push(
2374
+ () => provider.off("connect", handlers.connect),
2375
+ () => provider.off("disconnect", handlers.disconnect),
2376
+ () => provider.off("accountsChanged", handlers.accountsChanged)
2377
+ );
2432
2378
  }
2433
- if (!this.selectedWalletId || this.externalWalletEventListenersSetup.has(this.selectedWalletId)) {
2379
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2380
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2381
+ }
2382
+ /**
2383
+ * Unified event listener setup for all wallet types (Phantom and external).
2384
+ * Cleans up listeners for previously selected wallets to prevent stale events
2385
+ * from causing walletId flicker during connections.
2386
+ */
2387
+ setupEventListeners(walletInfo) {
2388
+ const walletId = this.selectedWalletId || "phantom";
2389
+ if (this.eventListenersSetup.has(walletId)) {
2390
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Event listeners already set up for wallet", { walletId });
2434
2391
  return;
2435
2392
  }
2436
- debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up external wallet event listeners", {
2437
- walletId: this.selectedWalletId
2438
- });
2439
- if (walletInfo.providers?.ethereum) {
2440
- const handleExternalEthereumAccountsChanged = async (accounts) => {
2441
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum accounts changed event received", {
2442
- walletId: this.selectedWalletId,
2443
- accounts
2444
- });
2445
- const walletId = this.selectedWalletId;
2446
- const state = this.getWalletState(walletId);
2447
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2448
- if (accounts && accounts.length > 0) {
2449
- const ethAddresses = accounts.map((address) => ({ addressType: AddressType2.ethereum, address }));
2450
- const newAddresses = [...otherAddresses, ...ethAddresses];
2451
- this.setWalletState(walletId, {
2452
- connected: true,
2453
- addresses: newAddresses
2454
- });
2455
- debug.log(DebugCategory.INJECTED_PROVIDER, "Updated Ethereum addresses after account change", {
2456
- walletId,
2457
- oldCount: 0,
2458
- // We filtered them out
2459
- newCount: accounts.length,
2460
- addresses: newAddresses.filter((addr) => addr.addressType === AddressType2.ethereum)
2461
- });
2462
- const authUserId = await this.getAuthUserId("External wallet Ethereum accounts changed event");
2463
- this.emit("connect", {
2464
- addresses: newAddresses,
2465
- source: "external-wallet-account-change",
2466
- authUserId
2467
- });
2468
- } else {
2469
- this.setWalletState(walletId, {
2470
- connected: otherAddresses.length > 0,
2471
- addresses: otherAddresses
2472
- });
2473
- this.emit("disconnect", {
2474
- source: "external-wallet-account-change"
2475
- });
2476
- }
2477
- };
2478
- if (typeof walletInfo.providers.ethereum.on === "function") {
2479
- walletInfo.providers.ethereum.on("accountsChanged", handleExternalEthereumAccountsChanged);
2480
- this.browserInjectedCleanupFunctions.push(() => {
2481
- if (typeof walletInfo.providers?.ethereum?.off === "function") {
2482
- walletInfo.providers.ethereum.off("accountsChanged", handleExternalEthereumAccountsChanged);
2483
- }
2484
- });
2393
+ for (const existingWalletId of this.eventListenersSetup) {
2394
+ if (existingWalletId === walletId) {
2395
+ continue;
2485
2396
  }
2486
- }
2487
- if (walletInfo.providers?.solana) {
2488
- const handleExternalSolanaAccountChanged = async (publicKey) => {
2489
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana account changed event received", {
2490
- walletId: this.selectedWalletId,
2491
- publicKey
2492
- });
2493
- const walletId = this.selectedWalletId;
2494
- const state = this.getWalletState(walletId);
2495
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
2496
- if (publicKey) {
2497
- const newAddresses = [...otherAddresses, { addressType: AddressType2.solana, address: publicKey }];
2498
- this.setWalletState(walletId, {
2499
- connected: true,
2500
- addresses: newAddresses
2501
- });
2502
- const authUserId = await this.getAuthUserId("External wallet Solana account changed event");
2503
- this.emit("connect", {
2504
- addresses: newAddresses,
2505
- source: "external-wallet-account-change",
2506
- authUserId
2507
- });
2508
- } else {
2509
- this.setWalletState(walletId, {
2510
- connected: otherAddresses.length > 0,
2511
- addresses: otherAddresses
2512
- });
2513
- this.emit("disconnect", {
2514
- source: "external-wallet-account-change"
2515
- });
2516
- }
2517
- };
2518
- if (typeof walletInfo.providers.solana.on === "function") {
2519
- walletInfo.providers.solana.on("accountChanged", handleExternalSolanaAccountChanged);
2520
- this.browserInjectedCleanupFunctions.push(() => {
2521
- if (typeof walletInfo.providers?.solana?.off === "function") {
2522
- walletInfo.providers.solana.off("accountChanged", handleExternalSolanaAccountChanged);
2523
- }
2524
- });
2397
+ const cleanups = this.eventListenerCleanups.get(existingWalletId);
2398
+ if (cleanups) {
2399
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Cleaning up event listeners for wallet", { existingWalletId });
2400
+ cleanups.forEach((cleanup) => cleanup());
2525
2401
  }
2402
+ this.eventListenersSetup.delete(existingWalletId);
2526
2403
  }
2527
- if (this.selectedWalletId) {
2528
- this.externalWalletEventListenersSetup.add(this.selectedWalletId);
2404
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up event listeners", { walletId });
2405
+ if (this.addressTypes.includes(AddressType3.solana) && walletInfo.providers?.solana) {
2406
+ this.setupSolanaEventListeners(walletInfo.providers.solana, walletId, "wallet");
2407
+ }
2408
+ if (this.addressTypes.includes(AddressType3.ethereum) && walletInfo.providers?.ethereum) {
2409
+ this.setupEthereumEventListeners(walletInfo.providers.ethereum, walletId, "wallet");
2529
2410
  }
2411
+ this.eventListenersSetup.add(walletId);
2412
+ this.eventsInitialized = true;
2530
2413
  }
2531
2414
  };
2532
2415
 
@@ -2666,7 +2549,7 @@ var BrowserURLParamsAccessor = class {
2666
2549
  var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
2667
2550
 
2668
2551
  // src/providers/embedded/adapters/auth.ts
2669
- import { DEFAULT_AUTH_URL } from "@phantom/constants";
2552
+ import { DEFAULT_AUTH_URL, DEFAULT_AUTHENTICATOR_ALGORITHM } from "@phantom/constants";
2670
2553
 
2671
2554
  // src/utils/browser-detection.ts
2672
2555
  function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
@@ -2841,9 +2724,10 @@ var BrowserAuthProvider = class {
2841
2724
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2842
2725
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2843
2726
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2844
- sdk_version: "1.0.0",
2727
+ sdk_version: "1.0.3",
2845
2728
  sdk_type: "browser",
2846
- platform: detectBrowser().name
2729
+ platform: detectBrowser().name,
2730
+ algorithm: phantomOptions.algorithm || DEFAULT_AUTHENTICATOR_ALGORITHM
2847
2731
  });
2848
2732
  if (phantomOptions.provider) {
2849
2733
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
@@ -2964,28 +2848,9 @@ var BrowserAuthProvider = class {
2964
2848
  // src/providers/embedded/adapters/phantom-app.ts
2965
2849
  import { isPhantomExtensionInstalled as isPhantomExtensionInstalled3 } from "@phantom/browser-injected-sdk";
2966
2850
 
2967
- // src/isPhantomLoginAvailable.ts
2851
+ // src/waitForPhantomExtension.ts
2968
2852
  import { isPhantomExtensionInstalled as isPhantomExtensionInstalled2 } from "@phantom/browser-injected-sdk";
2969
- async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2970
- const extensionInstalled = await waitForExtension(timeoutMs);
2971
- if (!extensionInstalled) {
2972
- return false;
2973
- }
2974
- try {
2975
- if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2976
- return false;
2977
- }
2978
- const response = await window.phantom.app.features();
2979
- if (!Array.isArray(response.features)) {
2980
- return false;
2981
- }
2982
- return response.features.includes("phantom_login");
2983
- } catch (error) {
2984
- console.error("Error checking Phantom extension features", error);
2985
- return false;
2986
- }
2987
- }
2988
- async function waitForExtension(timeoutMs) {
2853
+ async function waitForPhantomExtension(timeoutMs = 3e3) {
2989
2854
  return new Promise((resolve) => {
2990
2855
  const startTime = Date.now();
2991
2856
  const checkInterval = 100;
@@ -3008,6 +2873,27 @@ async function waitForExtension(timeoutMs) {
3008
2873
  });
3009
2874
  }
3010
2875
 
2876
+ // src/isPhantomLoginAvailable.ts
2877
+ async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2878
+ const extensionInstalled = await waitForPhantomExtension(timeoutMs);
2879
+ if (!extensionInstalled) {
2880
+ return false;
2881
+ }
2882
+ try {
2883
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2884
+ return false;
2885
+ }
2886
+ const response = await window.phantom.app.features();
2887
+ if (!Array.isArray(response.features)) {
2888
+ return false;
2889
+ }
2890
+ return response.features.includes("phantom_login");
2891
+ } catch (error) {
2892
+ console.error("Error checking Phantom extension features", error);
2893
+ return false;
2894
+ }
2895
+ }
2896
+
3011
2897
  // src/providers/embedded/adapters/phantom-app.ts
3012
2898
  var BrowserPhantomAppProvider = class {
3013
2899
  /**
@@ -3105,7 +2991,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
3105
2991
  // Full user agent for more detailed info
3106
2992
  [ANALYTICS_HEADERS.APP_ID]: config.appId,
3107
2993
  [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3108
- [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0"
2994
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.3"
3109
2995
  // Replaced at build time
3110
2996
  }
3111
2997
  };
@@ -3144,11 +3030,12 @@ function isAuthCallbackUrl(searchParams) {
3144
3030
  }
3145
3031
 
3146
3032
  // src/utils/deeplink.ts
3147
- function getDeeplinkToPhantom(ref) {
3148
- if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
3033
+ function getDeeplinkToPhantom(ref, currentHref) {
3034
+ const resolvedHref = currentHref ?? window.location.href;
3035
+ if (!resolvedHref.startsWith("http:") && !resolvedHref.startsWith("https:")) {
3149
3036
  throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
3150
3037
  }
3151
- const currentUrl = encodeURIComponent(window.location.href);
3038
+ const currentUrl = encodeURIComponent(resolvedHref);
3152
3039
  const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
3153
3040
  return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
3154
3041
  }
@@ -3244,8 +3131,14 @@ var ProviderManager = class {
3244
3131
  } else if (requestedProvider === "deeplink") {
3245
3132
  try {
3246
3133
  const deeplinkUrl = getDeeplinkToPhantom();
3247
- if (typeof window !== "undefined") {
3248
- window.location.href = deeplinkUrl;
3134
+ if (typeof window !== "undefined" && window.location) {
3135
+ try {
3136
+ window.location.href = deeplinkUrl;
3137
+ } catch (error) {
3138
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "Failed to set deeplink location", {
3139
+ error: error instanceof Error ? error.message : String(error)
3140
+ });
3141
+ }
3249
3142
  }
3250
3143
  return {
3251
3144
  addresses: [],
@@ -3390,7 +3283,7 @@ var ProviderManager = class {
3390
3283
  if (!this.eventListeners.has(event)) {
3391
3284
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
3392
3285
  }
3393
- this.eventListeners.get(event).add(callback);
3286
+ this.eventListeners.get(event)?.add(callback);
3394
3287
  this.ensureProviderEventForwarding();
3395
3288
  }
3396
3289
  /**
@@ -3399,8 +3292,8 @@ var ProviderManager = class {
3399
3292
  off(event, callback) {
3400
3293
  debug.log(DebugCategory.PROVIDER_MANAGER, "Removing event listener", { event });
3401
3294
  if (this.eventListeners.has(event)) {
3402
- this.eventListeners.get(event).delete(callback);
3403
- if (this.eventListeners.get(event).size === 0) {
3295
+ this.eventListeners.get(event)?.delete(callback);
3296
+ if (this.eventListeners.get(event)?.size === 0) {
3404
3297
  this.eventListeners.delete(event);
3405
3298
  }
3406
3299
  }
@@ -3716,6 +3609,7 @@ var BrowserSDK = class {
3716
3609
  */
3717
3610
  async autoConnect() {
3718
3611
  debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect with fallback strategy");
3612
+ await this.discoverWallets();
3719
3613
  const result = await this.providerManager.autoConnect();
3720
3614
  if (result) {
3721
3615
  debug.info(DebugCategory.BROWSER_SDK, "Auto-connect successful", {
@@ -3863,40 +3757,17 @@ var BrowserSDK = class {
3863
3757
  }
3864
3758
  };
3865
3759
 
3866
- // src/waitForPhantomExtension.ts
3867
- import { isPhantomExtensionInstalled as isPhantomExtensionInstalled4 } from "@phantom/browser-injected-sdk";
3868
- async function waitForPhantomExtension(timeoutMs = 3e3) {
3869
- return new Promise((resolve) => {
3870
- const startTime = Date.now();
3871
- const checkInterval = 100;
3872
- const checkForExtension = () => {
3873
- try {
3874
- if (isPhantomExtensionInstalled4()) {
3875
- resolve(true);
3876
- return;
3877
- }
3878
- } catch (error) {
3879
- }
3880
- const elapsed = Date.now() - startTime;
3881
- if (elapsed >= timeoutMs) {
3882
- resolve(false);
3883
- return;
3884
- }
3885
- setTimeout(checkForExtension, checkInterval);
3886
- };
3887
- checkForExtension();
3888
- });
3889
- }
3890
-
3891
3760
  // src/index.ts
3892
3761
  import { NetworkId } from "@phantom/constants";
3893
- import { AddressType as AddressType3 } from "@phantom/client";
3762
+ import { AddressType as AddressType4 } from "@phantom/client";
3763
+ import { PHANTOM_ICON as PHANTOM_ICON3 } from "@phantom/constants";
3894
3764
  export {
3895
- AddressType3 as AddressType,
3765
+ AddressType4 as AddressType,
3896
3766
  BrowserSDK,
3897
3767
  DebugCategory,
3898
3768
  DebugLevel,
3899
3769
  NetworkId,
3770
+ PHANTOM_ICON3 as PHANTOM_ICON,
3900
3771
  debug,
3901
3772
  detectBrowser,
3902
3773
  getBrowserDisplayName,