@phantom/browser-sdk 1.0.0 → 1.0.2

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.
Files changed (3) hide show
  1. package/dist/index.js +376 -550
  2. package/dist/index.mjs +378 -552
  3. package/package.json +10 -10
package/dist/index.js CHANGED
@@ -346,7 +346,7 @@ async function discoverSolanaWallets() {
346
346
  return chainLower.startsWith("solana:") || chainLower === "solana";
347
347
  }) || wallet.features && typeof wallet.features === "object" && Object.keys(wallet.features).some((featureKey) => {
348
348
  const featureLower = featureKey.toLowerCase();
349
- return featureLower.includes("solana") || featureLower.includes("standard:connect") || featureLower.includes("standard:signTransaction");
349
+ return featureLower.startsWith("solana:");
350
350
  });
351
351
  if (!supportsSolana) {
352
352
  const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
@@ -493,6 +493,7 @@ var import_eventemitter3 = require("eventemitter3");
493
493
  var import_buffer = require("buffer");
494
494
  var InjectedWalletSolanaChain = class {
495
495
  constructor(provider, walletId, walletName) {
496
+ // Expose eventEmitter for testing - allows tests to trigger events directly
496
497
  this.eventEmitter = new import_eventemitter3.EventEmitter();
497
498
  this._connected = false;
498
499
  this._publicKey = null;
@@ -721,6 +722,7 @@ var InjectedWalletSolanaChain = class {
721
722
  });
722
723
  this.provider.on("accountChanged", (publicKey) => {
723
724
  this._publicKey = publicKey;
725
+ this._connected = publicKey != null && publicKey.length > 0;
724
726
  this.eventEmitter.emit("accountChanged", publicKey);
725
727
  });
726
728
  }
@@ -734,26 +736,29 @@ var InjectedWalletSolanaChain = class {
734
736
  };
735
737
 
736
738
  // src/providers/injected/chains/WalletStandardSolanaAdapter.ts
739
+ var import_eventemitter32 = require("eventemitter3");
737
740
  var import_parsers = require("@phantom/parsers");
741
+ var import_buffer2 = require("buffer");
738
742
  var import_bs58 = __toESM(require("bs58"));
739
743
  var WalletStandardSolanaAdapter = class {
740
744
  constructor(wallet, walletId, walletName) {
741
- this._connected = false;
745
+ this.eventEmitter = new import_eventemitter32.EventEmitter();
742
746
  this._publicKey = null;
743
747
  this.wallet = wallet;
744
748
  this.walletId = walletId;
745
749
  this.walletName = walletName;
750
+ this.setupEventListeners();
746
751
  }
747
752
  get connected() {
748
- return this._connected;
753
+ return this._publicKey !== null;
749
754
  }
750
755
  get publicKey() {
751
756
  return this._publicKey;
752
757
  }
753
758
  async connect(_options) {
754
759
  try {
755
- const connectFeature = this.wallet.features?.["standard:connect"];
756
- if (!connectFeature || typeof connectFeature.connect !== "function") {
760
+ const connectFeature = this.wallet.features["standard:connect"];
761
+ if (!connectFeature) {
757
762
  throw new Error("Wallet Standard connect feature not available");
758
763
  }
759
764
  const connectResult = await connectFeature.connect();
@@ -774,14 +779,13 @@ var WalletStandardSolanaAdapter = class {
774
779
  if (typeof firstAccount === "string") {
775
780
  address = firstAccount;
776
781
  } 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);
782
+ address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? import_buffer2.Buffer.from(firstAccount.publicKey).toString("hex") : void 0);
778
783
  }
779
784
  if (!address) {
780
785
  throw new Error(
781
786
  `Could not extract address from account. Account structure: ${JSON.stringify(firstAccount, null, 2)}`
782
787
  );
783
788
  }
784
- this._connected = true;
785
789
  this._publicKey = address;
786
790
  return { publicKey: address };
787
791
  } catch (error) {
@@ -795,11 +799,10 @@ var WalletStandardSolanaAdapter = class {
795
799
  }
796
800
  async disconnect() {
797
801
  try {
798
- const disconnectFeature = this.wallet.features?.["standard:disconnect"];
799
- if (disconnectFeature && typeof disconnectFeature.disconnect === "function") {
802
+ const disconnectFeature = this.wallet.features["standard:disconnect"];
803
+ if (disconnectFeature) {
800
804
  await disconnectFeature.disconnect();
801
805
  }
802
- this._connected = false;
803
806
  this._publicKey = null;
804
807
  } catch (error) {
805
808
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana disconnect failed", {
@@ -812,14 +815,14 @@ var WalletStandardSolanaAdapter = class {
812
815
  }
813
816
  async signMessage(message) {
814
817
  try {
815
- const signMessageFeature = this.wallet.features?.["solana:signMessage"];
816
- if (!signMessageFeature || typeof signMessageFeature.signMessage !== "function") {
818
+ const signMessageFeature = this.wallet.features["solana:signMessage"];
819
+ if (!signMessageFeature) {
817
820
  throw new Error("Wallet Standard signMessage feature not available");
818
821
  }
819
822
  const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
820
823
  const result = await signMessageFeature.signMessage({
821
824
  message: messageBytes,
822
- account: this.wallet.accounts?.[0]
825
+ account: this.wallet.accounts[0]
823
826
  });
824
827
  if (!Array.isArray(result) || result.length === 0) {
825
828
  throw new Error(`Expected array result from signMessage, got: ${typeof result}`);
@@ -832,7 +835,7 @@ var WalletStandardSolanaAdapter = class {
832
835
  if (signature.length === 0) {
833
836
  throw new Error(`Signature is empty`);
834
837
  }
835
- const publicKey = signedMessageResult.account?.address || this.wallet.accounts?.[0]?.address || this._publicKey || "";
838
+ const publicKey = signedMessageResult.account?.address || this.wallet.accounts[0]?.address || this._publicKey || "";
836
839
  return { signature, publicKey };
837
840
  } catch (error) {
838
841
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signMessage failed", {
@@ -845,8 +848,8 @@ var WalletStandardSolanaAdapter = class {
845
848
  }
846
849
  async signTransaction(transaction) {
847
850
  try {
848
- const signTransactionFeature = this.wallet.features?.["solana:signTransaction"];
849
- if (!signTransactionFeature || typeof signTransactionFeature.signTransaction !== "function") {
851
+ const signTransactionFeature = this.wallet.features["solana:signTransaction"];
852
+ if (!signTransactionFeature) {
850
853
  throw new Error("Wallet Standard signTransaction feature not available");
851
854
  }
852
855
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -865,7 +868,8 @@ var WalletStandardSolanaAdapter = class {
865
868
  transactionData = firstItem.signedTransaction || firstItem.transaction;
866
869
  }
867
870
  } else if (results && typeof results === "object" && !Array.isArray(results)) {
868
- transactionData = results.transaction || results.signedTransaction;
871
+ const resultObj = results;
872
+ transactionData = resultObj.transaction || resultObj.signedTransaction;
869
873
  }
870
874
  if (!transactionData) {
871
875
  throw new Error("No transaction data found in Wallet Standard result");
@@ -887,8 +891,8 @@ var WalletStandardSolanaAdapter = class {
887
891
  }
888
892
  async signAndSendTransaction(transaction) {
889
893
  try {
890
- const signAndSendTransactionFeature = this.wallet.features?.["solana:signAndSendTransaction"];
891
- if (!signAndSendTransactionFeature || typeof signAndSendTransactionFeature.signAndSendTransaction !== "function") {
894
+ const signAndSendTransactionFeature = this.wallet.features["solana:signAndSendTransaction"];
895
+ if (!signAndSendTransactionFeature) {
892
896
  throw new Error("Wallet Standard signAndSendTransaction feature not available");
893
897
  }
894
898
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -959,40 +963,93 @@ var WalletStandardSolanaAdapter = class {
959
963
  throw error;
960
964
  }
961
965
  }
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", {
971
- walletId: this.walletId,
972
- walletName: this.walletName,
973
- network,
974
- error: error instanceof Error ? error.message : String(error)
975
- });
976
- throw error;
977
- }
966
+ async switchNetwork(_network) {
967
+ return Promise.resolve();
978
968
  }
979
969
  getPublicKey() {
980
970
  return Promise.resolve(this._publicKey);
981
971
  }
982
972
  isConnected() {
983
- return this._connected;
973
+ return this._publicKey !== null;
984
974
  }
985
- on(_event, _listener) {
986
- const eventsFeature = this.wallet.features?.["standard:events"];
987
- if (eventsFeature && typeof eventsFeature.on === "function") {
988
- eventsFeature.on(_event, _listener);
975
+ /**
976
+ * Set up event listeners for Wallet Standard events
977
+ * Maps Wallet Standard "change" events to "accountChanged" events
978
+ *
979
+ * Note: Wallet Standard only has a "change" event. There are no "connect" or "disconnect" events.
980
+ * Connection/disconnection is indicated by the presence or absence of accounts in the change event.
981
+ */
982
+ setupEventListeners() {
983
+ const eventsFeature = this.wallet.features["standard:events"];
984
+ if (!eventsFeature) {
985
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard events feature not available", {
986
+ walletId: this.walletId,
987
+ walletName: this.walletName
988
+ });
989
+ return;
989
990
  }
991
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Wallet Standard event listeners", {
992
+ walletId: this.walletId,
993
+ walletName: this.walletName
994
+ });
995
+ eventsFeature.on("change", (properties) => {
996
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard change event received", {
997
+ walletId: this.walletId,
998
+ walletName: this.walletName,
999
+ hasAccounts: !!properties.accounts,
1000
+ accountCount: properties.accounts?.length || 0
1001
+ });
1002
+ if (properties.accounts !== void 0) {
1003
+ if (properties.accounts.length > 0) {
1004
+ const firstAccount = properties.accounts[0];
1005
+ const address = this.extractAccountAddress(firstAccount);
1006
+ if (address) {
1007
+ this._publicKey = address;
1008
+ this.eventEmitter.emit("accountChanged", address);
1009
+ this.eventEmitter.emit("connect", address);
1010
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and connect events", {
1011
+ walletId: this.walletId,
1012
+ walletName: this.walletName,
1013
+ address
1014
+ });
1015
+ } else {
1016
+ this._publicKey = null;
1017
+ this.eventEmitter.emit("accountChanged", null);
1018
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged event (null - invalid account)", {
1019
+ walletId: this.walletId,
1020
+ walletName: this.walletName
1021
+ });
1022
+ }
1023
+ } else {
1024
+ this._publicKey = null;
1025
+ this.eventEmitter.emit("accountChanged", null);
1026
+ this.eventEmitter.emit("disconnect");
1027
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and disconnect events", {
1028
+ walletId: this.walletId,
1029
+ walletName: this.walletName
1030
+ });
1031
+ }
1032
+ }
1033
+ });
990
1034
  }
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
- }
1035
+ extractAccountAddress(account) {
1036
+ return account.address;
1037
+ }
1038
+ on(event, listener) {
1039
+ this.eventEmitter.on(event, listener);
1040
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Added event listener", {
1041
+ walletId: this.walletId,
1042
+ walletName: this.walletName,
1043
+ event
1044
+ });
1045
+ }
1046
+ off(event, listener) {
1047
+ this.eventEmitter.off(event, listener);
1048
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Removed event listener", {
1049
+ walletId: this.walletId,
1050
+ walletName: this.walletName,
1051
+ event
1052
+ });
996
1053
  }
997
1054
  /**
998
1055
  * Serialize a transaction to Uint8Array for Wallet Standard API
@@ -1036,10 +1093,11 @@ var WalletStandardSolanaAdapter = class {
1036
1093
  };
1037
1094
 
1038
1095
  // src/providers/injected/chains/InjectedWalletEthereumChain.ts
1039
- var import_eventemitter32 = require("eventemitter3");
1096
+ var import_eventemitter33 = require("eventemitter3");
1040
1097
  var InjectedWalletEthereumChain = class {
1041
1098
  constructor(provider, walletId, walletName) {
1042
- this.eventEmitter = new import_eventemitter32.EventEmitter();
1099
+ // Expose eventEmitter for testing - allows tests to trigger events directly
1100
+ this.eventEmitter = new import_eventemitter33.EventEmitter();
1043
1101
  this._connected = false;
1044
1102
  this._chainId = "0x1";
1045
1103
  this._accounts = [];
@@ -1413,6 +1471,7 @@ var InjectedWalletEthereumChain = class {
1413
1471
  });
1414
1472
  this.provider.on("accountsChanged", (accounts) => {
1415
1473
  this._accounts = accounts;
1474
+ this._connected = accounts.length > 0;
1416
1475
  this.eventEmitter.emit("accountsChanged", accounts);
1417
1476
  });
1418
1477
  this.provider.on("chainChanged", (chainId) => {
@@ -1429,218 +1488,13 @@ var InjectedWalletEthereumChain = class {
1429
1488
  }
1430
1489
  };
1431
1490
 
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
1491
  // src/wallets/registry.ts
1641
1492
  function isPhantomWallet(wallet) {
1642
1493
  return wallet !== void 0 && wallet.id === "phantom" && "isPhantom" in wallet && wallet.isPhantom === true;
1643
1494
  }
1495
+ function isWalletStandardWallet(provider) {
1496
+ return provider !== null && typeof provider === "object" && "features" in provider && typeof provider.features === "object";
1497
+ }
1644
1498
  var InjectedWalletRegistry = class {
1645
1499
  constructor() {
1646
1500
  this.wallets = /* @__PURE__ */ new Map();
@@ -1649,8 +1503,7 @@ var InjectedWalletRegistry = class {
1649
1503
  register(info) {
1650
1504
  const wrappedProviders = {};
1651
1505
  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) {
1506
+ if (isWalletStandardWallet(info.providers.solana)) {
1654
1507
  wrappedProviders.solana = new WalletStandardSolanaAdapter(info.providers.solana, info.id, info.name);
1655
1508
  debug.log(DebugCategory.BROWSER_SDK, "Wrapped Wallet Standard Solana wallet with adapter", {
1656
1509
  walletId: info.id,
@@ -1680,18 +1533,19 @@ var InjectedWalletRegistry = class {
1680
1533
  /**
1681
1534
  * Register Phantom wallet with its instance
1682
1535
  * This creates wrapped providers and stores the Phantom instance for auto-confirm access
1536
+ * Uses unified InjectedWallet chains for both Phantom and external wallets
1683
1537
  */
1684
1538
  registerPhantom(phantomInstance, addressTypes) {
1685
1539
  const wrappedProviders = {};
1686
1540
  if (addressTypes.includes(import_client.AddressType.solana) && phantomInstance.solana) {
1687
- wrappedProviders.solana = new PhantomSolanaChain(phantomInstance);
1688
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomSolanaChain wrapper", {
1541
+ wrappedProviders.solana = new InjectedWalletSolanaChain(phantomInstance.solana, "phantom", "Phantom");
1542
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletSolanaChain wrapper for Phantom", {
1689
1543
  walletId: "phantom"
1690
1544
  });
1691
1545
  }
1692
1546
  if (addressTypes.includes(import_client.AddressType.ethereum) && phantomInstance.ethereum) {
1693
- wrappedProviders.ethereum = new PhantomEthereumChain(phantomInstance);
1694
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomEthereumChain wrapper", {
1547
+ wrappedProviders.ethereum = new InjectedWalletEthereumChain(phantomInstance.ethereum, "phantom", "Phantom");
1548
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletEthereumChain wrapper for Phantom", {
1695
1549
  walletId: "phantom"
1696
1550
  });
1697
1551
  }
@@ -1776,15 +1630,16 @@ var WAS_CONNECTED_KEY = "phantom-injected-was-connected";
1776
1630
  var WAS_CONNECTED_VALUE = "true";
1777
1631
  var LAST_WALLET_ID_KEY = "phantom-injected-last-wallet-id";
1778
1632
  var InjectedProvider = class {
1779
- // Track which wallets have event listeners set up
1633
+ // Store cleanups per walletId
1780
1634
  constructor(config) {
1781
1635
  this.selectedWalletId = null;
1782
1636
  this.walletStates = /* @__PURE__ */ new Map();
1783
1637
  // Event management
1784
1638
  this.eventListeners = /* @__PURE__ */ new Map();
1785
- this.browserInjectedCleanupFunctions = [];
1786
1639
  this.eventsInitialized = false;
1787
- this.externalWalletEventListenersSetup = /* @__PURE__ */ new Set();
1640
+ this.eventListenersSetup = /* @__PURE__ */ new Set();
1641
+ // Track walletId that have listeners set up
1642
+ this.eventListenerCleanups = /* @__PURE__ */ new Map();
1788
1643
  debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
1789
1644
  this.addressTypes = config.addressTypes;
1790
1645
  this.walletRegistry = getWalletRegistry();
@@ -1815,9 +1670,12 @@ var InjectedProvider = class {
1815
1670
  });
1816
1671
  }
1817
1672
  }
1818
- get solana() {
1819
- if (!this.addressTypes.includes(import_client3.AddressType.solana)) {
1820
- throw new Error("Solana not enabled for this provider");
1673
+ /**
1674
+ * Helper method to get a chain provider with consistent error handling
1675
+ */
1676
+ getChainProvider(addressType, providerKey, chainName) {
1677
+ if (!this.addressTypes.includes(addressType)) {
1678
+ throw new Error(`${chainName} not enabled for this provider`);
1821
1679
  }
1822
1680
  const walletId = this.selectedWalletId || "phantom";
1823
1681
  const walletInfo = this.walletRegistry.getById(walletId);
@@ -1832,39 +1690,22 @@ var InjectedProvider = class {
1832
1690
  `Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
1833
1691
  );
1834
1692
  }
1835
- if (!walletInfo.providers?.solana) {
1693
+ const provider = walletInfo.providers?.[providerKey];
1694
+ if (!provider) {
1836
1695
  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.`
1696
+ `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
1697
  );
1839
1698
  }
1840
- return walletInfo.providers.solana;
1699
+ return provider;
1700
+ }
1701
+ get solana() {
1702
+ return this.getChainProvider(import_client3.AddressType.solana, "solana", "Solana");
1841
1703
  }
1842
1704
  /**
1843
1705
  * Access to Ethereum chain operations
1844
1706
  */
1845
1707
  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;
1708
+ return this.getChainProvider(import_client3.AddressType.ethereum, "ethereum", "Ethereum");
1868
1709
  }
1869
1710
  validateAndSelectWallet(requestedWalletId) {
1870
1711
  if (!this.walletRegistry.has(requestedWalletId)) {
@@ -1902,13 +1743,7 @@ var InjectedProvider = class {
1902
1743
  options
1903
1744
  });
1904
1745
  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
- }
1746
+ this.setupEventListeners(walletInfo);
1912
1747
  }
1913
1748
  const connectedAddresses = [];
1914
1749
  if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers?.solana) {
@@ -2090,10 +1925,14 @@ var InjectedProvider = class {
2090
1925
  }
2091
1926
  }
2092
1927
  }
2093
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
2094
- this.browserInjectedCleanupFunctions = [];
1928
+ const walletId = this.selectedWalletId || "phantom";
1929
+ const cleanups = this.eventListenerCleanups.get(walletId);
1930
+ if (cleanups) {
1931
+ cleanups.forEach((cleanup) => cleanup());
1932
+ this.eventListenerCleanups.delete(walletId);
1933
+ }
1934
+ this.eventListenersSetup.delete(walletId);
2095
1935
  if (this.selectedWalletId) {
2096
- this.externalWalletEventListenersSetup.delete(this.selectedWalletId);
2097
1936
  this.setWalletState(this.selectedWalletId, {
2098
1937
  connected: false,
2099
1938
  addresses: []
@@ -2162,13 +2001,7 @@ var InjectedProvider = class {
2162
2001
  });
2163
2002
  return;
2164
2003
  }
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
- }
2004
+ this.setupEventListeners(walletInfo);
2172
2005
  if (this.selectedWalletId) {
2173
2006
  this.setWalletState(this.selectedWalletId, {
2174
2007
  connected: true,
@@ -2209,6 +2042,166 @@ var InjectedProvider = class {
2209
2042
  setWalletState(walletId, state) {
2210
2043
  this.walletStates.set(walletId, state);
2211
2044
  }
2045
+ /**
2046
+ * Update wallet state with new addresses for a specific address type
2047
+ * Replaces all existing addresses of the given type with the new addresses
2048
+ * @param walletId - The wallet ID to update
2049
+ * @param newAddresses - Array of new addresses (strings) for the address type
2050
+ * @param addressType - The type of addresses being updated
2051
+ * @returns The updated addresses array
2052
+ */
2053
+ updateWalletAddresses(walletId, newAddresses, addressType) {
2054
+ const state = this.getWalletState(walletId);
2055
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== addressType);
2056
+ const addressesOfType = newAddresses.map((address) => ({ addressType, address }));
2057
+ const updatedAddresses = [...otherAddresses, ...addressesOfType];
2058
+ this.setWalletState(walletId, {
2059
+ connected: updatedAddresses.length > 0,
2060
+ addresses: updatedAddresses
2061
+ });
2062
+ return updatedAddresses;
2063
+ }
2064
+ /**
2065
+ * Helper to construct account change source string
2066
+ */
2067
+ getAccountChangeSource(source) {
2068
+ return `${source}-account-change`;
2069
+ }
2070
+ /**
2071
+ * Create a handler for Solana connect events
2072
+ */
2073
+ createSolanaConnectHandler(walletId, source) {
2074
+ return async (publicKey) => {
2075
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey, walletId });
2076
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client3.AddressType.solana);
2077
+ const authUserId = await this.getAuthUserId("Solana connect event");
2078
+ this.emit("connect", {
2079
+ addresses: newAddresses,
2080
+ source,
2081
+ authUserId
2082
+ });
2083
+ };
2084
+ }
2085
+ /**
2086
+ * Create a handler for Solana disconnect events
2087
+ */
2088
+ createSolanaDisconnectHandler(walletId, source) {
2089
+ return () => {
2090
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received", { walletId });
2091
+ const state = this.getWalletState(walletId);
2092
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
2093
+ this.setWalletState(walletId, {
2094
+ connected: filteredAddresses.length > 0,
2095
+ addresses: filteredAddresses
2096
+ });
2097
+ this.emit("disconnect", {
2098
+ source
2099
+ });
2100
+ };
2101
+ }
2102
+ /**
2103
+ * Create a handler for Solana account change events
2104
+ * Can receive string | null per Wallet Standard
2105
+ */
2106
+ createSolanaAccountChangeHandler(walletId, source) {
2107
+ return async (publicKey) => {
2108
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey, walletId });
2109
+ if (publicKey) {
2110
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client3.AddressType.solana);
2111
+ const authUserId = await this.getAuthUserId("Solana account changed event");
2112
+ this.emit("connect", {
2113
+ addresses: newAddresses,
2114
+ source: this.getAccountChangeSource(source),
2115
+ authUserId
2116
+ });
2117
+ } else {
2118
+ const state = this.getWalletState(walletId);
2119
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
2120
+ this.setWalletState(walletId, {
2121
+ connected: otherAddresses.length > 0,
2122
+ addresses: otherAddresses
2123
+ });
2124
+ this.emit("disconnect", {
2125
+ source: this.getAccountChangeSource(source)
2126
+ });
2127
+ }
2128
+ };
2129
+ }
2130
+ /**
2131
+ * Create a handler for Ethereum connect events
2132
+ * EIP-1193 connect event receives { chainId: string }, but we need to get accounts separately
2133
+ */
2134
+ createEthereumConnectHandler(walletId, source) {
2135
+ return async (connectInfo) => {
2136
+ let accounts = [];
2137
+ if (Array.isArray(connectInfo)) {
2138
+ accounts = connectInfo;
2139
+ } else {
2140
+ try {
2141
+ const walletInfo = this.walletRegistry.getById(walletId);
2142
+ if (walletInfo?.providers?.ethereum) {
2143
+ accounts = await walletInfo.providers.ethereum.getAccounts();
2144
+ }
2145
+ } catch (error) {
2146
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to get accounts on connect", { error });
2147
+ }
2148
+ }
2149
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts, walletId });
2150
+ if (accounts.length > 0) {
2151
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client3.AddressType.ethereum);
2152
+ const authUserId = await this.getAuthUserId("Ethereum connect event");
2153
+ this.emit("connect", {
2154
+ addresses: newAddresses,
2155
+ source,
2156
+ authUserId
2157
+ });
2158
+ }
2159
+ };
2160
+ }
2161
+ /**
2162
+ * Create a handler for Ethereum disconnect events
2163
+ */
2164
+ createEthereumDisconnectHandler(walletId, source) {
2165
+ return () => {
2166
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received", { walletId });
2167
+ const state = this.getWalletState(walletId);
2168
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2169
+ this.setWalletState(walletId, {
2170
+ connected: filteredAddresses.length > 0,
2171
+ addresses: filteredAddresses
2172
+ });
2173
+ this.emit("disconnect", {
2174
+ source
2175
+ });
2176
+ };
2177
+ }
2178
+ /**
2179
+ * Create a handler for Ethereum account change events
2180
+ */
2181
+ createEthereumAccountChangeHandler(walletId, source) {
2182
+ return async (accounts) => {
2183
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts, walletId });
2184
+ if (accounts && accounts.length > 0) {
2185
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client3.AddressType.ethereum);
2186
+ const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2187
+ this.emit("connect", {
2188
+ addresses: newAddresses,
2189
+ source: this.getAccountChangeSource(source),
2190
+ authUserId
2191
+ });
2192
+ } else {
2193
+ const state = this.getWalletState(walletId);
2194
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2195
+ this.setWalletState(walletId, {
2196
+ connected: otherAddresses.length > 0,
2197
+ addresses: otherAddresses
2198
+ });
2199
+ this.emit("disconnect", {
2200
+ source: this.getAccountChangeSource(source)
2201
+ });
2202
+ }
2203
+ };
2204
+ }
2212
2205
  getAddresses() {
2213
2206
  const walletId = this.selectedWalletId || "phantom";
2214
2207
  return this.getWalletState(walletId).addresses;
@@ -2302,19 +2295,22 @@ var InjectedProvider = class {
2302
2295
  on(event, callback) {
2303
2296
  debug.log(DebugCategory.INJECTED_PROVIDER, "Adding event listener", { event });
2304
2297
  if (!this.eventsInitialized) {
2305
- this.setupBrowserInjectedEvents();
2306
- this.eventsInitialized = true;
2298
+ const walletId = this.selectedWalletId || "phantom";
2299
+ const walletInfo = this.walletRegistry.getById(walletId);
2300
+ if (walletInfo) {
2301
+ this.setupEventListeners(walletInfo);
2302
+ }
2307
2303
  }
2308
2304
  if (!this.eventListeners.has(event)) {
2309
2305
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
2310
2306
  }
2311
- this.eventListeners.get(event).add(callback);
2307
+ this.eventListeners.get(event)?.add(callback);
2312
2308
  }
2313
2309
  off(event, callback) {
2314
2310
  debug.log(DebugCategory.INJECTED_PROVIDER, "Removing event listener", { event });
2315
2311
  if (this.eventListeners.has(event)) {
2316
- this.eventListeners.get(event).delete(callback);
2317
- if (this.eventListeners.get(event).size === 0) {
2312
+ this.eventListeners.get(event)?.delete(callback);
2313
+ if (this.eventListeners.get(event)?.size === 0) {
2318
2314
  this.eventListeners.delete(event);
2319
2315
  }
2320
2316
  }
@@ -2336,246 +2332,76 @@ var InjectedProvider = class {
2336
2332
  });
2337
2333
  }
2338
2334
  }
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");
2335
+ /**
2336
+ * Set up Solana event listeners for any provider (Phantom or external)
2337
+ */
2338
+ setupSolanaEventListeners(provider, walletId, source) {
2339
+ if (typeof provider.on !== "function")
2343
2340
  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
- });
2374
- };
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
- }
2341
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners", { walletId, source });
2342
+ const handlers = {
2343
+ connect: this.createSolanaConnectHandler(walletId, source),
2344
+ disconnect: this.createSolanaDisconnectHandler(walletId, source),
2345
+ accountChanged: this.createSolanaAccountChangeHandler(walletId, source)
2472
2346
  };
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);
2347
+ provider.on("connect", handlers.connect);
2348
+ provider.on("disconnect", handlers.disconnect);
2349
+ provider.on("accountChanged", handlers.accountChanged);
2350
+ const cleanups = [];
2351
+ if (typeof provider.off === "function") {
2352
+ cleanups.push(
2353
+ () => provider.off("connect", handlers.connect),
2354
+ () => provider.off("disconnect", handlers.disconnect),
2355
+ () => provider.off("accountChanged", handlers.accountChanged)
2356
+ );
2357
+ }
2358
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2359
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2477
2360
  }
2478
- setupExternalWalletEvents(walletInfo) {
2479
- if (isPhantomWallet(walletInfo)) {
2361
+ /**
2362
+ * Set up Ethereum event listeners for any provider (Phantom or external)
2363
+ */
2364
+ setupEthereumEventListeners(provider, walletId, source) {
2365
+ if (typeof provider.on !== "function")
2480
2366
  return;
2367
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners", { walletId, source });
2368
+ const handlers = {
2369
+ connect: this.createEthereumConnectHandler(walletId, source),
2370
+ disconnect: this.createEthereumDisconnectHandler(walletId, source),
2371
+ accountsChanged: this.createEthereumAccountChangeHandler(walletId, source)
2372
+ };
2373
+ provider.on("connect", handlers.connect);
2374
+ provider.on("disconnect", handlers.disconnect);
2375
+ provider.on("accountsChanged", handlers.accountsChanged);
2376
+ const cleanups = [];
2377
+ if (typeof provider.off === "function") {
2378
+ cleanups.push(
2379
+ () => provider.off("connect", handlers.connect),
2380
+ () => provider.off("disconnect", handlers.disconnect),
2381
+ () => provider.off("accountsChanged", handlers.accountsChanged)
2382
+ );
2481
2383
  }
2482
- if (!this.selectedWalletId || this.externalWalletEventListenersSetup.has(this.selectedWalletId)) {
2384
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2385
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2386
+ }
2387
+ /**
2388
+ * Unified event listener setup for all wallet types (Phantom and external)
2389
+ */
2390
+ setupEventListeners(walletInfo) {
2391
+ const walletId = this.selectedWalletId || "phantom";
2392
+ if (this.eventListenersSetup.has(walletId)) {
2393
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Event listeners already set up for wallet", { walletId });
2483
2394
  return;
2484
2395
  }
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
- });
2534
- }
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
- });
2574
- }
2396
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up event listeners", { walletId });
2397
+ if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers?.solana) {
2398
+ this.setupSolanaEventListeners(walletInfo.providers.solana, walletId, "wallet");
2575
2399
  }
2576
- if (this.selectedWalletId) {
2577
- this.externalWalletEventListenersSetup.add(this.selectedWalletId);
2400
+ if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers?.ethereum) {
2401
+ this.setupEthereumEventListeners(walletInfo.providers.ethereum, walletId, "wallet");
2578
2402
  }
2403
+ this.eventListenersSetup.add(walletId);
2404
+ this.eventsInitialized = true;
2579
2405
  }
2580
2406
  };
2581
2407
 
@@ -2890,7 +2716,7 @@ var BrowserAuthProvider = class {
2890
2716
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2891
2717
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2892
2718
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2893
- sdk_version: "1.0.0",
2719
+ sdk_version: "1.0.2",
2894
2720
  sdk_type: "browser",
2895
2721
  platform: detectBrowser().name
2896
2722
  });
@@ -3154,7 +2980,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
3154
2980
  // Full user agent for more detailed info
3155
2981
  [import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
3156
2982
  [import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3157
- [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0"
2983
+ [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.2"
3158
2984
  // Replaced at build time
3159
2985
  }
3160
2986
  };
@@ -3437,7 +3263,7 @@ var ProviderManager = class {
3437
3263
  if (!this.eventListeners.has(event)) {
3438
3264
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
3439
3265
  }
3440
- this.eventListeners.get(event).add(callback);
3266
+ this.eventListeners.get(event)?.add(callback);
3441
3267
  this.ensureProviderEventForwarding();
3442
3268
  }
3443
3269
  /**
@@ -3446,8 +3272,8 @@ var ProviderManager = class {
3446
3272
  off(event, callback) {
3447
3273
  debug.log(DebugCategory.PROVIDER_MANAGER, "Removing event listener", { event });
3448
3274
  if (this.eventListeners.has(event)) {
3449
- this.eventListeners.get(event).delete(callback);
3450
- if (this.eventListeners.get(event).size === 0) {
3275
+ this.eventListeners.get(event)?.delete(callback);
3276
+ if (this.eventListeners.get(event)?.size === 0) {
3451
3277
  this.eventListeners.delete(event);
3452
3278
  }
3453
3279
  }