@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.mjs CHANGED
@@ -297,7 +297,7 @@ async function discoverSolanaWallets() {
297
297
  return chainLower.startsWith("solana:") || chainLower === "solana";
298
298
  }) || wallet.features && typeof wallet.features === "object" && Object.keys(wallet.features).some((featureKey) => {
299
299
  const featureLower = featureKey.toLowerCase();
300
- return featureLower.includes("solana") || featureLower.includes("standard:connect") || featureLower.includes("standard:signTransaction");
300
+ return featureLower.startsWith("solana:");
301
301
  });
302
302
  if (!supportsSolana) {
303
303
  const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
@@ -441,9 +441,10 @@ async function discoverWallets(addressTypes) {
441
441
 
442
442
  // src/providers/injected/chains/InjectedWalletSolanaChain.ts
443
443
  import { EventEmitter } from "eventemitter3";
444
- import { Buffer as Buffer2 } from "buffer";
444
+ import { Buffer } from "buffer";
445
445
  var InjectedWalletSolanaChain = class {
446
446
  constructor(provider, walletId, walletName) {
447
+ // Expose eventEmitter for testing - allows tests to trigger events directly
447
448
  this.eventEmitter = new EventEmitter();
448
449
  this._connected = false;
449
450
  this._publicKey = null;
@@ -548,7 +549,7 @@ var InjectedWalletSolanaChain = class {
548
549
  signatureLength: result.signature.length
549
550
  });
550
551
  return {
551
- signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(Buffer2.from(result.signature, "base64")),
552
+ signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(Buffer.from(result.signature, "base64")),
552
553
  publicKey: result.publicKey || this._publicKey || ""
553
554
  };
554
555
  } catch (error) {
@@ -672,6 +673,7 @@ var InjectedWalletSolanaChain = class {
672
673
  });
673
674
  this.provider.on("accountChanged", (publicKey) => {
674
675
  this._publicKey = publicKey;
676
+ this._connected = publicKey != null && publicKey.length > 0;
675
677
  this.eventEmitter.emit("accountChanged", publicKey);
676
678
  });
677
679
  }
@@ -685,26 +687,29 @@ var InjectedWalletSolanaChain = class {
685
687
  };
686
688
 
687
689
  // src/providers/injected/chains/WalletStandardSolanaAdapter.ts
690
+ import { EventEmitter as EventEmitter2 } from "eventemitter3";
688
691
  import { deserializeSolanaTransaction } from "@phantom/parsers";
692
+ import { Buffer as Buffer2 } from "buffer";
689
693
  import bs58 from "bs58";
690
694
  var WalletStandardSolanaAdapter = class {
691
695
  constructor(wallet, walletId, walletName) {
692
- this._connected = false;
696
+ this.eventEmitter = new EventEmitter2();
693
697
  this._publicKey = null;
694
698
  this.wallet = wallet;
695
699
  this.walletId = walletId;
696
700
  this.walletName = walletName;
701
+ this.setupEventListeners();
697
702
  }
698
703
  get connected() {
699
- return this._connected;
704
+ return this._publicKey !== null;
700
705
  }
701
706
  get publicKey() {
702
707
  return this._publicKey;
703
708
  }
704
709
  async connect(_options) {
705
710
  try {
706
- const connectFeature = this.wallet.features?.["standard:connect"];
707
- if (!connectFeature || typeof connectFeature.connect !== "function") {
711
+ const connectFeature = this.wallet.features["standard:connect"];
712
+ if (!connectFeature) {
708
713
  throw new Error("Wallet Standard connect feature not available");
709
714
  }
710
715
  const connectResult = await connectFeature.connect();
@@ -725,14 +730,13 @@ var WalletStandardSolanaAdapter = class {
725
730
  if (typeof firstAccount === "string") {
726
731
  address = firstAccount;
727
732
  } 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);
733
+ address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? Buffer2.from(firstAccount.publicKey).toString("hex") : void 0);
729
734
  }
730
735
  if (!address) {
731
736
  throw new Error(
732
737
  `Could not extract address from account. Account structure: ${JSON.stringify(firstAccount, null, 2)}`
733
738
  );
734
739
  }
735
- this._connected = true;
736
740
  this._publicKey = address;
737
741
  return { publicKey: address };
738
742
  } catch (error) {
@@ -746,11 +750,10 @@ var WalletStandardSolanaAdapter = class {
746
750
  }
747
751
  async disconnect() {
748
752
  try {
749
- const disconnectFeature = this.wallet.features?.["standard:disconnect"];
750
- if (disconnectFeature && typeof disconnectFeature.disconnect === "function") {
753
+ const disconnectFeature = this.wallet.features["standard:disconnect"];
754
+ if (disconnectFeature) {
751
755
  await disconnectFeature.disconnect();
752
756
  }
753
- this._connected = false;
754
757
  this._publicKey = null;
755
758
  } catch (error) {
756
759
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana disconnect failed", {
@@ -763,14 +766,14 @@ var WalletStandardSolanaAdapter = class {
763
766
  }
764
767
  async signMessage(message) {
765
768
  try {
766
- const signMessageFeature = this.wallet.features?.["solana:signMessage"];
767
- if (!signMessageFeature || typeof signMessageFeature.signMessage !== "function") {
769
+ const signMessageFeature = this.wallet.features["solana:signMessage"];
770
+ if (!signMessageFeature) {
768
771
  throw new Error("Wallet Standard signMessage feature not available");
769
772
  }
770
773
  const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
771
774
  const result = await signMessageFeature.signMessage({
772
775
  message: messageBytes,
773
- account: this.wallet.accounts?.[0]
776
+ account: this.wallet.accounts[0]
774
777
  });
775
778
  if (!Array.isArray(result) || result.length === 0) {
776
779
  throw new Error(`Expected array result from signMessage, got: ${typeof result}`);
@@ -783,7 +786,7 @@ var WalletStandardSolanaAdapter = class {
783
786
  if (signature.length === 0) {
784
787
  throw new Error(`Signature is empty`);
785
788
  }
786
- const publicKey = signedMessageResult.account?.address || this.wallet.accounts?.[0]?.address || this._publicKey || "";
789
+ const publicKey = signedMessageResult.account?.address || this.wallet.accounts[0]?.address || this._publicKey || "";
787
790
  return { signature, publicKey };
788
791
  } catch (error) {
789
792
  debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signMessage failed", {
@@ -796,8 +799,8 @@ var WalletStandardSolanaAdapter = class {
796
799
  }
797
800
  async signTransaction(transaction) {
798
801
  try {
799
- const signTransactionFeature = this.wallet.features?.["solana:signTransaction"];
800
- if (!signTransactionFeature || typeof signTransactionFeature.signTransaction !== "function") {
802
+ const signTransactionFeature = this.wallet.features["solana:signTransaction"];
803
+ if (!signTransactionFeature) {
801
804
  throw new Error("Wallet Standard signTransaction feature not available");
802
805
  }
803
806
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -816,7 +819,8 @@ var WalletStandardSolanaAdapter = class {
816
819
  transactionData = firstItem.signedTransaction || firstItem.transaction;
817
820
  }
818
821
  } else if (results && typeof results === "object" && !Array.isArray(results)) {
819
- transactionData = results.transaction || results.signedTransaction;
822
+ const resultObj = results;
823
+ transactionData = resultObj.transaction || resultObj.signedTransaction;
820
824
  }
821
825
  if (!transactionData) {
822
826
  throw new Error("No transaction data found in Wallet Standard result");
@@ -838,8 +842,8 @@ var WalletStandardSolanaAdapter = class {
838
842
  }
839
843
  async signAndSendTransaction(transaction) {
840
844
  try {
841
- const signAndSendTransactionFeature = this.wallet.features?.["solana:signAndSendTransaction"];
842
- if (!signAndSendTransactionFeature || typeof signAndSendTransactionFeature.signAndSendTransaction !== "function") {
845
+ const signAndSendTransactionFeature = this.wallet.features["solana:signAndSendTransaction"];
846
+ if (!signAndSendTransactionFeature) {
843
847
  throw new Error("Wallet Standard signAndSendTransaction feature not available");
844
848
  }
845
849
  if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
@@ -910,40 +914,93 @@ var WalletStandardSolanaAdapter = class {
910
914
  throw error;
911
915
  }
912
916
  }
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", {
922
- walletId: this.walletId,
923
- walletName: this.walletName,
924
- network,
925
- error: error instanceof Error ? error.message : String(error)
926
- });
927
- throw error;
928
- }
917
+ async switchNetwork(_network) {
918
+ return Promise.resolve();
929
919
  }
930
920
  getPublicKey() {
931
921
  return Promise.resolve(this._publicKey);
932
922
  }
933
923
  isConnected() {
934
- return this._connected;
924
+ return this._publicKey !== null;
935
925
  }
936
- on(_event, _listener) {
937
- const eventsFeature = this.wallet.features?.["standard:events"];
938
- if (eventsFeature && typeof eventsFeature.on === "function") {
939
- eventsFeature.on(_event, _listener);
926
+ /**
927
+ * Set up event listeners for Wallet Standard events
928
+ * Maps Wallet Standard "change" events to "accountChanged" events
929
+ *
930
+ * Note: Wallet Standard only has a "change" event. There are no "connect" or "disconnect" events.
931
+ * Connection/disconnection is indicated by the presence or absence of accounts in the change event.
932
+ */
933
+ setupEventListeners() {
934
+ const eventsFeature = this.wallet.features["standard:events"];
935
+ if (!eventsFeature) {
936
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard events feature not available", {
937
+ walletId: this.walletId,
938
+ walletName: this.walletName
939
+ });
940
+ return;
940
941
  }
942
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Wallet Standard event listeners", {
943
+ walletId: this.walletId,
944
+ walletName: this.walletName
945
+ });
946
+ eventsFeature.on("change", (properties) => {
947
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet Standard change event received", {
948
+ walletId: this.walletId,
949
+ walletName: this.walletName,
950
+ hasAccounts: !!properties.accounts,
951
+ accountCount: properties.accounts?.length || 0
952
+ });
953
+ if (properties.accounts !== void 0) {
954
+ if (properties.accounts.length > 0) {
955
+ const firstAccount = properties.accounts[0];
956
+ const address = this.extractAccountAddress(firstAccount);
957
+ if (address) {
958
+ this._publicKey = address;
959
+ this.eventEmitter.emit("accountChanged", address);
960
+ this.eventEmitter.emit("connect", address);
961
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and connect events", {
962
+ walletId: this.walletId,
963
+ walletName: this.walletName,
964
+ address
965
+ });
966
+ } else {
967
+ this._publicKey = null;
968
+ this.eventEmitter.emit("accountChanged", null);
969
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged event (null - invalid account)", {
970
+ walletId: this.walletId,
971
+ walletName: this.walletName
972
+ });
973
+ }
974
+ } else {
975
+ this._publicKey = null;
976
+ this.eventEmitter.emit("accountChanged", null);
977
+ this.eventEmitter.emit("disconnect");
978
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitted accountChanged and disconnect events", {
979
+ walletId: this.walletId,
980
+ walletName: this.walletName
981
+ });
982
+ }
983
+ }
984
+ });
941
985
  }
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
- }
986
+ extractAccountAddress(account) {
987
+ return account.address;
988
+ }
989
+ on(event, listener) {
990
+ this.eventEmitter.on(event, listener);
991
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Added event listener", {
992
+ walletId: this.walletId,
993
+ walletName: this.walletName,
994
+ event
995
+ });
996
+ }
997
+ off(event, listener) {
998
+ this.eventEmitter.off(event, listener);
999
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Removed event listener", {
1000
+ walletId: this.walletId,
1001
+ walletName: this.walletName,
1002
+ event
1003
+ });
947
1004
  }
948
1005
  /**
949
1006
  * Serialize a transaction to Uint8Array for Wallet Standard API
@@ -987,10 +1044,11 @@ var WalletStandardSolanaAdapter = class {
987
1044
  };
988
1045
 
989
1046
  // src/providers/injected/chains/InjectedWalletEthereumChain.ts
990
- import { EventEmitter as EventEmitter2 } from "eventemitter3";
1047
+ import { EventEmitter as EventEmitter3 } from "eventemitter3";
991
1048
  var InjectedWalletEthereumChain = class {
992
1049
  constructor(provider, walletId, walletName) {
993
- this.eventEmitter = new EventEmitter2();
1050
+ // Expose eventEmitter for testing - allows tests to trigger events directly
1051
+ this.eventEmitter = new EventEmitter3();
994
1052
  this._connected = false;
995
1053
  this._chainId = "0x1";
996
1054
  this._accounts = [];
@@ -1364,6 +1422,7 @@ var InjectedWalletEthereumChain = class {
1364
1422
  });
1365
1423
  this.provider.on("accountsChanged", (accounts) => {
1366
1424
  this._accounts = accounts;
1425
+ this._connected = accounts.length > 0;
1367
1426
  this.eventEmitter.emit("accountsChanged", accounts);
1368
1427
  });
1369
1428
  this.provider.on("chainChanged", (chainId) => {
@@ -1380,218 +1439,13 @@ var InjectedWalletEthereumChain = class {
1380
1439
  }
1381
1440
  };
1382
1441
 
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
1442
  // src/wallets/registry.ts
1592
1443
  function isPhantomWallet(wallet) {
1593
1444
  return wallet !== void 0 && wallet.id === "phantom" && "isPhantom" in wallet && wallet.isPhantom === true;
1594
1445
  }
1446
+ function isWalletStandardWallet(provider) {
1447
+ return provider !== null && typeof provider === "object" && "features" in provider && typeof provider.features === "object";
1448
+ }
1595
1449
  var InjectedWalletRegistry = class {
1596
1450
  constructor() {
1597
1451
  this.wallets = /* @__PURE__ */ new Map();
@@ -1600,8 +1454,7 @@ var InjectedWalletRegistry = class {
1600
1454
  register(info) {
1601
1455
  const wrappedProviders = {};
1602
1456
  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) {
1457
+ if (isWalletStandardWallet(info.providers.solana)) {
1605
1458
  wrappedProviders.solana = new WalletStandardSolanaAdapter(info.providers.solana, info.id, info.name);
1606
1459
  debug.log(DebugCategory.BROWSER_SDK, "Wrapped Wallet Standard Solana wallet with adapter", {
1607
1460
  walletId: info.id,
@@ -1631,18 +1484,19 @@ var InjectedWalletRegistry = class {
1631
1484
  /**
1632
1485
  * Register Phantom wallet with its instance
1633
1486
  * This creates wrapped providers and stores the Phantom instance for auto-confirm access
1487
+ * Uses unified InjectedWallet chains for both Phantom and external wallets
1634
1488
  */
1635
1489
  registerPhantom(phantomInstance, addressTypes) {
1636
1490
  const wrappedProviders = {};
1637
1491
  if (addressTypes.includes(AddressType.solana) && phantomInstance.solana) {
1638
- wrappedProviders.solana = new PhantomSolanaChain(phantomInstance);
1639
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomSolanaChain wrapper", {
1492
+ wrappedProviders.solana = new InjectedWalletSolanaChain(phantomInstance.solana, "phantom", "Phantom");
1493
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletSolanaChain wrapper for Phantom", {
1640
1494
  walletId: "phantom"
1641
1495
  });
1642
1496
  }
1643
1497
  if (addressTypes.includes(AddressType.ethereum) && phantomInstance.ethereum) {
1644
- wrappedProviders.ethereum = new PhantomEthereumChain(phantomInstance);
1645
- debug.log(DebugCategory.BROWSER_SDK, "Created PhantomEthereumChain wrapper", {
1498
+ wrappedProviders.ethereum = new InjectedWalletEthereumChain(phantomInstance.ethereum, "phantom", "Phantom");
1499
+ debug.log(DebugCategory.BROWSER_SDK, "Created InjectedWalletEthereumChain wrapper for Phantom", {
1646
1500
  walletId: "phantom"
1647
1501
  });
1648
1502
  }
@@ -1727,15 +1581,16 @@ var WAS_CONNECTED_KEY = "phantom-injected-was-connected";
1727
1581
  var WAS_CONNECTED_VALUE = "true";
1728
1582
  var LAST_WALLET_ID_KEY = "phantom-injected-last-wallet-id";
1729
1583
  var InjectedProvider = class {
1730
- // Track which wallets have event listeners set up
1584
+ // Store cleanups per walletId
1731
1585
  constructor(config) {
1732
1586
  this.selectedWalletId = null;
1733
1587
  this.walletStates = /* @__PURE__ */ new Map();
1734
1588
  // Event management
1735
1589
  this.eventListeners = /* @__PURE__ */ new Map();
1736
- this.browserInjectedCleanupFunctions = [];
1737
1590
  this.eventsInitialized = false;
1738
- this.externalWalletEventListenersSetup = /* @__PURE__ */ new Set();
1591
+ this.eventListenersSetup = /* @__PURE__ */ new Set();
1592
+ // Track walletId that have listeners set up
1593
+ this.eventListenerCleanups = /* @__PURE__ */ new Map();
1739
1594
  debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
1740
1595
  this.addressTypes = config.addressTypes;
1741
1596
  this.walletRegistry = getWalletRegistry();
@@ -1766,9 +1621,12 @@ var InjectedProvider = class {
1766
1621
  });
1767
1622
  }
1768
1623
  }
1769
- get solana() {
1770
- if (!this.addressTypes.includes(AddressType2.solana)) {
1771
- throw new Error("Solana not enabled for this provider");
1624
+ /**
1625
+ * Helper method to get a chain provider with consistent error handling
1626
+ */
1627
+ getChainProvider(addressType, providerKey, chainName) {
1628
+ if (!this.addressTypes.includes(addressType)) {
1629
+ throw new Error(`${chainName} not enabled for this provider`);
1772
1630
  }
1773
1631
  const walletId = this.selectedWalletId || "phantom";
1774
1632
  const walletInfo = this.walletRegistry.getById(walletId);
@@ -1783,39 +1641,22 @@ var InjectedProvider = class {
1783
1641
  `Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
1784
1642
  );
1785
1643
  }
1786
- if (!walletInfo.providers?.solana) {
1644
+ const provider = walletInfo.providers?.[providerKey];
1645
+ if (!provider) {
1787
1646
  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.`
1647
+ `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
1648
  );
1790
1649
  }
1791
- return walletInfo.providers.solana;
1650
+ return provider;
1651
+ }
1652
+ get solana() {
1653
+ return this.getChainProvider(AddressType2.solana, "solana", "Solana");
1792
1654
  }
1793
1655
  /**
1794
1656
  * Access to Ethereum chain operations
1795
1657
  */
1796
1658
  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;
1659
+ return this.getChainProvider(AddressType2.ethereum, "ethereum", "Ethereum");
1819
1660
  }
1820
1661
  validateAndSelectWallet(requestedWalletId) {
1821
1662
  if (!this.walletRegistry.has(requestedWalletId)) {
@@ -1853,13 +1694,7 @@ var InjectedProvider = class {
1853
1694
  options
1854
1695
  });
1855
1696
  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
- }
1697
+ this.setupEventListeners(walletInfo);
1863
1698
  }
1864
1699
  const connectedAddresses = [];
1865
1700
  if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers?.solana) {
@@ -2041,10 +1876,14 @@ var InjectedProvider = class {
2041
1876
  }
2042
1877
  }
2043
1878
  }
2044
- this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
2045
- this.browserInjectedCleanupFunctions = [];
1879
+ const walletId = this.selectedWalletId || "phantom";
1880
+ const cleanups = this.eventListenerCleanups.get(walletId);
1881
+ if (cleanups) {
1882
+ cleanups.forEach((cleanup) => cleanup());
1883
+ this.eventListenerCleanups.delete(walletId);
1884
+ }
1885
+ this.eventListenersSetup.delete(walletId);
2046
1886
  if (this.selectedWalletId) {
2047
- this.externalWalletEventListenersSetup.delete(this.selectedWalletId);
2048
1887
  this.setWalletState(this.selectedWalletId, {
2049
1888
  connected: false,
2050
1889
  addresses: []
@@ -2113,13 +1952,7 @@ var InjectedProvider = class {
2113
1952
  });
2114
1953
  return;
2115
1954
  }
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
- }
1955
+ this.setupEventListeners(walletInfo);
2123
1956
  if (this.selectedWalletId) {
2124
1957
  this.setWalletState(this.selectedWalletId, {
2125
1958
  connected: true,
@@ -2160,6 +1993,166 @@ var InjectedProvider = class {
2160
1993
  setWalletState(walletId, state) {
2161
1994
  this.walletStates.set(walletId, state);
2162
1995
  }
1996
+ /**
1997
+ * Update wallet state with new addresses for a specific address type
1998
+ * Replaces all existing addresses of the given type with the new addresses
1999
+ * @param walletId - The wallet ID to update
2000
+ * @param newAddresses - Array of new addresses (strings) for the address type
2001
+ * @param addressType - The type of addresses being updated
2002
+ * @returns The updated addresses array
2003
+ */
2004
+ updateWalletAddresses(walletId, newAddresses, addressType) {
2005
+ const state = this.getWalletState(walletId);
2006
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== addressType);
2007
+ const addressesOfType = newAddresses.map((address) => ({ addressType, address }));
2008
+ const updatedAddresses = [...otherAddresses, ...addressesOfType];
2009
+ this.setWalletState(walletId, {
2010
+ connected: updatedAddresses.length > 0,
2011
+ addresses: updatedAddresses
2012
+ });
2013
+ return updatedAddresses;
2014
+ }
2015
+ /**
2016
+ * Helper to construct account change source string
2017
+ */
2018
+ getAccountChangeSource(source) {
2019
+ return `${source}-account-change`;
2020
+ }
2021
+ /**
2022
+ * Create a handler for Solana connect events
2023
+ */
2024
+ createSolanaConnectHandler(walletId, source) {
2025
+ return async (publicKey) => {
2026
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey, walletId });
2027
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType2.solana);
2028
+ const authUserId = await this.getAuthUserId("Solana connect event");
2029
+ this.emit("connect", {
2030
+ addresses: newAddresses,
2031
+ source,
2032
+ authUserId
2033
+ });
2034
+ };
2035
+ }
2036
+ /**
2037
+ * Create a handler for Solana disconnect events
2038
+ */
2039
+ createSolanaDisconnectHandler(walletId, source) {
2040
+ return () => {
2041
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received", { walletId });
2042
+ const state = this.getWalletState(walletId);
2043
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
2044
+ this.setWalletState(walletId, {
2045
+ connected: filteredAddresses.length > 0,
2046
+ addresses: filteredAddresses
2047
+ });
2048
+ this.emit("disconnect", {
2049
+ source
2050
+ });
2051
+ };
2052
+ }
2053
+ /**
2054
+ * Create a handler for Solana account change events
2055
+ * Can receive string | null per Wallet Standard
2056
+ */
2057
+ createSolanaAccountChangeHandler(walletId, source) {
2058
+ return async (publicKey) => {
2059
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey, walletId });
2060
+ if (publicKey) {
2061
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType2.solana);
2062
+ const authUserId = await this.getAuthUserId("Solana account changed event");
2063
+ this.emit("connect", {
2064
+ addresses: newAddresses,
2065
+ source: this.getAccountChangeSource(source),
2066
+ authUserId
2067
+ });
2068
+ } else {
2069
+ const state = this.getWalletState(walletId);
2070
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
2071
+ this.setWalletState(walletId, {
2072
+ connected: otherAddresses.length > 0,
2073
+ addresses: otherAddresses
2074
+ });
2075
+ this.emit("disconnect", {
2076
+ source: this.getAccountChangeSource(source)
2077
+ });
2078
+ }
2079
+ };
2080
+ }
2081
+ /**
2082
+ * Create a handler for Ethereum connect events
2083
+ * EIP-1193 connect event receives { chainId: string }, but we need to get accounts separately
2084
+ */
2085
+ createEthereumConnectHandler(walletId, source) {
2086
+ return async (connectInfo) => {
2087
+ let accounts = [];
2088
+ if (Array.isArray(connectInfo)) {
2089
+ accounts = connectInfo;
2090
+ } else {
2091
+ try {
2092
+ const walletInfo = this.walletRegistry.getById(walletId);
2093
+ if (walletInfo?.providers?.ethereum) {
2094
+ accounts = await walletInfo.providers.ethereum.getAccounts();
2095
+ }
2096
+ } catch (error) {
2097
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to get accounts on connect", { error });
2098
+ }
2099
+ }
2100
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts, walletId });
2101
+ if (accounts.length > 0) {
2102
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType2.ethereum);
2103
+ const authUserId = await this.getAuthUserId("Ethereum connect event");
2104
+ this.emit("connect", {
2105
+ addresses: newAddresses,
2106
+ source,
2107
+ authUserId
2108
+ });
2109
+ }
2110
+ };
2111
+ }
2112
+ /**
2113
+ * Create a handler for Ethereum disconnect events
2114
+ */
2115
+ createEthereumDisconnectHandler(walletId, source) {
2116
+ return () => {
2117
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received", { walletId });
2118
+ const state = this.getWalletState(walletId);
2119
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2120
+ this.setWalletState(walletId, {
2121
+ connected: filteredAddresses.length > 0,
2122
+ addresses: filteredAddresses
2123
+ });
2124
+ this.emit("disconnect", {
2125
+ source
2126
+ });
2127
+ };
2128
+ }
2129
+ /**
2130
+ * Create a handler for Ethereum account change events
2131
+ */
2132
+ createEthereumAccountChangeHandler(walletId, source) {
2133
+ return async (accounts) => {
2134
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts, walletId });
2135
+ if (accounts && accounts.length > 0) {
2136
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType2.ethereum);
2137
+ const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2138
+ this.emit("connect", {
2139
+ addresses: newAddresses,
2140
+ source: this.getAccountChangeSource(source),
2141
+ authUserId
2142
+ });
2143
+ } else {
2144
+ const state = this.getWalletState(walletId);
2145
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2146
+ this.setWalletState(walletId, {
2147
+ connected: otherAddresses.length > 0,
2148
+ addresses: otherAddresses
2149
+ });
2150
+ this.emit("disconnect", {
2151
+ source: this.getAccountChangeSource(source)
2152
+ });
2153
+ }
2154
+ };
2155
+ }
2163
2156
  getAddresses() {
2164
2157
  const walletId = this.selectedWalletId || "phantom";
2165
2158
  return this.getWalletState(walletId).addresses;
@@ -2253,19 +2246,22 @@ var InjectedProvider = class {
2253
2246
  on(event, callback) {
2254
2247
  debug.log(DebugCategory.INJECTED_PROVIDER, "Adding event listener", { event });
2255
2248
  if (!this.eventsInitialized) {
2256
- this.setupBrowserInjectedEvents();
2257
- this.eventsInitialized = true;
2249
+ const walletId = this.selectedWalletId || "phantom";
2250
+ const walletInfo = this.walletRegistry.getById(walletId);
2251
+ if (walletInfo) {
2252
+ this.setupEventListeners(walletInfo);
2253
+ }
2258
2254
  }
2259
2255
  if (!this.eventListeners.has(event)) {
2260
2256
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
2261
2257
  }
2262
- this.eventListeners.get(event).add(callback);
2258
+ this.eventListeners.get(event)?.add(callback);
2263
2259
  }
2264
2260
  off(event, callback) {
2265
2261
  debug.log(DebugCategory.INJECTED_PROVIDER, "Removing event listener", { event });
2266
2262
  if (this.eventListeners.has(event)) {
2267
- this.eventListeners.get(event).delete(callback);
2268
- if (this.eventListeners.get(event).size === 0) {
2263
+ this.eventListeners.get(event)?.delete(callback);
2264
+ if (this.eventListeners.get(event)?.size === 0) {
2269
2265
  this.eventListeners.delete(event);
2270
2266
  }
2271
2267
  }
@@ -2287,246 +2283,76 @@ var InjectedProvider = class {
2287
2283
  });
2288
2284
  }
2289
2285
  }
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");
2286
+ /**
2287
+ * Set up Solana event listeners for any provider (Phantom or external)
2288
+ */
2289
+ setupSolanaEventListeners(provider, walletId, source) {
2290
+ if (typeof provider.on !== "function")
2294
2291
  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
- });
2338
- };
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
- }
2292
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners", { walletId, source });
2293
+ const handlers = {
2294
+ connect: this.createSolanaConnectHandler(walletId, source),
2295
+ disconnect: this.createSolanaDisconnectHandler(walletId, source),
2296
+ accountChanged: this.createSolanaAccountChangeHandler(walletId, source)
2423
2297
  };
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);
2298
+ provider.on("connect", handlers.connect);
2299
+ provider.on("disconnect", handlers.disconnect);
2300
+ provider.on("accountChanged", handlers.accountChanged);
2301
+ const cleanups = [];
2302
+ if (typeof provider.off === "function") {
2303
+ cleanups.push(
2304
+ () => provider.off("connect", handlers.connect),
2305
+ () => provider.off("disconnect", handlers.disconnect),
2306
+ () => provider.off("accountChanged", handlers.accountChanged)
2307
+ );
2308
+ }
2309
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2310
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2428
2311
  }
2429
- setupExternalWalletEvents(walletInfo) {
2430
- if (isPhantomWallet(walletInfo)) {
2312
+ /**
2313
+ * Set up Ethereum event listeners for any provider (Phantom or external)
2314
+ */
2315
+ setupEthereumEventListeners(provider, walletId, source) {
2316
+ if (typeof provider.on !== "function")
2431
2317
  return;
2318
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners", { walletId, source });
2319
+ const handlers = {
2320
+ connect: this.createEthereumConnectHandler(walletId, source),
2321
+ disconnect: this.createEthereumDisconnectHandler(walletId, source),
2322
+ accountsChanged: this.createEthereumAccountChangeHandler(walletId, source)
2323
+ };
2324
+ provider.on("connect", handlers.connect);
2325
+ provider.on("disconnect", handlers.disconnect);
2326
+ provider.on("accountsChanged", handlers.accountsChanged);
2327
+ const cleanups = [];
2328
+ if (typeof provider.off === "function") {
2329
+ cleanups.push(
2330
+ () => provider.off("connect", handlers.connect),
2331
+ () => provider.off("disconnect", handlers.disconnect),
2332
+ () => provider.off("accountsChanged", handlers.accountsChanged)
2333
+ );
2432
2334
  }
2433
- if (!this.selectedWalletId || this.externalWalletEventListenersSetup.has(this.selectedWalletId)) {
2335
+ const existingCleanups = this.eventListenerCleanups.get(walletId) || [];
2336
+ this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2337
+ }
2338
+ /**
2339
+ * Unified event listener setup for all wallet types (Phantom and external)
2340
+ */
2341
+ setupEventListeners(walletInfo) {
2342
+ const walletId = this.selectedWalletId || "phantom";
2343
+ if (this.eventListenersSetup.has(walletId)) {
2344
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Event listeners already set up for wallet", { walletId });
2434
2345
  return;
2435
2346
  }
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
- });
2485
- }
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
- });
2525
- }
2347
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up event listeners", { walletId });
2348
+ if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers?.solana) {
2349
+ this.setupSolanaEventListeners(walletInfo.providers.solana, walletId, "wallet");
2526
2350
  }
2527
- if (this.selectedWalletId) {
2528
- this.externalWalletEventListenersSetup.add(this.selectedWalletId);
2351
+ if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers?.ethereum) {
2352
+ this.setupEthereumEventListeners(walletInfo.providers.ethereum, walletId, "wallet");
2529
2353
  }
2354
+ this.eventListenersSetup.add(walletId);
2355
+ this.eventsInitialized = true;
2530
2356
  }
2531
2357
  };
2532
2358
 
@@ -2841,7 +2667,7 @@ var BrowserAuthProvider = class {
2841
2667
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2842
2668
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2843
2669
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2844
- sdk_version: "1.0.0",
2670
+ sdk_version: "1.0.2",
2845
2671
  sdk_type: "browser",
2846
2672
  platform: detectBrowser().name
2847
2673
  });
@@ -3105,7 +2931,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
3105
2931
  // Full user agent for more detailed info
3106
2932
  [ANALYTICS_HEADERS.APP_ID]: config.appId,
3107
2933
  [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3108
- [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0"
2934
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.2"
3109
2935
  // Replaced at build time
3110
2936
  }
3111
2937
  };
@@ -3390,7 +3216,7 @@ var ProviderManager = class {
3390
3216
  if (!this.eventListeners.has(event)) {
3391
3217
  this.eventListeners.set(event, /* @__PURE__ */ new Set());
3392
3218
  }
3393
- this.eventListeners.get(event).add(callback);
3219
+ this.eventListeners.get(event)?.add(callback);
3394
3220
  this.ensureProviderEventForwarding();
3395
3221
  }
3396
3222
  /**
@@ -3399,8 +3225,8 @@ var ProviderManager = class {
3399
3225
  off(event, callback) {
3400
3226
  debug.log(DebugCategory.PROVIDER_MANAGER, "Removing event listener", { event });
3401
3227
  if (this.eventListeners.has(event)) {
3402
- this.eventListeners.get(event).delete(callback);
3403
- if (this.eventListeners.get(event).size === 0) {
3228
+ this.eventListeners.get(event)?.delete(callback);
3229
+ if (this.eventListeners.get(event)?.size === 0) {
3404
3230
  this.eventListeners.delete(event);
3405
3231
  }
3406
3232
  }