@web3auth/no-modal 11.1.0 → 11.2.0

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 (41) hide show
  1. package/dist/lib.cjs/account-linking/react.js +1 -0
  2. package/dist/lib.cjs/account-linking/vue.js +1 -0
  3. package/dist/lib.cjs/base/connector/baseConnector.js +42 -11
  4. package/dist/lib.cjs/base/errors/index.js +5 -1
  5. package/dist/lib.cjs/base/utils.js +1 -1
  6. package/dist/lib.cjs/connectors/auth-connector/authConnector.js +15 -6
  7. package/dist/lib.cjs/connectors/coinbase-connector/coinbaseConnector.js +5 -5
  8. package/dist/lib.cjs/connectors/injected-evm-connector/injectedEvmConnector.js +6 -5
  9. package/dist/lib.cjs/connectors/injected-solana-connector/walletStandardConnector.js +6 -5
  10. package/dist/lib.cjs/connectors/metamask-connector/metamaskConnector.js +82 -31
  11. package/dist/lib.cjs/connectors/wallet-connect-v2-connector/walletConnectV2Connector.js +8 -6
  12. package/dist/lib.cjs/index.js +8 -7
  13. package/dist/lib.cjs/noModal.js +44 -21
  14. package/dist/lib.cjs/providers/account-abstraction-provider/providers/AccountAbstractionProvider.js +9 -2
  15. package/dist/lib.cjs/react/context/useWeb3AuthInnerContextValue.js +10 -0
  16. package/dist/lib.cjs/react/solana/provider.js +65 -32
  17. package/dist/lib.cjs/types/base/connector/baseConnector.d.ts +2 -1
  18. package/dist/lib.cjs/types/base/connector/interfaces.d.ts +1 -0
  19. package/dist/lib.cjs/types/base/errors/index.d.ts +1 -0
  20. package/dist/lib.cjs/types/base/interfaces.d.ts +2 -1
  21. package/dist/lib.cjs/types/connectors/metamask-connector/metamaskConnector.d.ts +1 -0
  22. package/dist/lib.cjs/types/vue/solana/provider.d.ts +2 -2
  23. package/dist/lib.cjs/vue/solana/provider.js +55 -21
  24. package/dist/lib.cjs/vue/useWeb3AuthInnerContextValue.js +12 -2
  25. package/dist/lib.esm/base/connector/baseConnector.js +42 -11
  26. package/dist/lib.esm/base/errors/index.js +5 -1
  27. package/dist/lib.esm/base/utils.js +1 -1
  28. package/dist/lib.esm/connectors/auth-connector/authConnector.js +13 -5
  29. package/dist/lib.esm/connectors/coinbase-connector/coinbaseConnector.js +5 -5
  30. package/dist/lib.esm/connectors/injected-evm-connector/injectedEvmConnector.js +6 -5
  31. package/dist/lib.esm/connectors/injected-solana-connector/walletStandardConnector.js +6 -5
  32. package/dist/lib.esm/connectors/metamask-connector/metamaskConnector.js +86 -31
  33. package/dist/lib.esm/connectors/wallet-connect-v2-connector/walletConnectV2Connector.js +8 -7
  34. package/dist/lib.esm/index.js +1 -1
  35. package/dist/lib.esm/noModal.js +44 -21
  36. package/dist/lib.esm/providers/account-abstraction-provider/providers/AccountAbstractionProvider.js +9 -2
  37. package/dist/lib.esm/react/context/useWeb3AuthInnerContextValue.js +10 -0
  38. package/dist/lib.esm/react/solana/provider.js +64 -30
  39. package/dist/lib.esm/vue/solana/provider.js +55 -19
  40. package/dist/lib.esm/vue/useWeb3AuthInnerContextValue.js +10 -0
  41. package/package.json +2 -2
@@ -19,7 +19,7 @@ import { assertAuthConnector, authConnector, isAuthConnector } from './connector
19
19
  import { AccountLinkingError } from './account-linking/errors.js';
20
20
  import { CommonJRPCProvider } from './providers/base-provider/CommonJRPCProvider.js';
21
21
  import { walletServicesPlugin } from './plugins/wallet-services-plugin/plugin.js';
22
- import { metaMaskConnector } from './connectors/metamask-connector/metamaskConnector.js';
22
+ import { metaMaskConnector, METAMASK_ERC_6963_PROVIDER_RDNS } from './connectors/metamask-connector/metamaskConnector.js';
23
23
  import { storageAvailable } from './base/connector/utils.js';
24
24
  import { PLUGIN_STATUS, PLUGIN_NAMESPACES } from './base/plugin/IPlugin.js';
25
25
 
@@ -50,7 +50,8 @@ class Web3AuthNoModal extends SafeEventEmitter {
50
50
  idToken: null,
51
51
  accessToken: null,
52
52
  refreshToken: null,
53
- activeAccount: null
53
+ activeAccount: null,
54
+ cachedConnectorNamespace: null
54
55
  });
55
56
  if (!options.clientId) throw WalletInitializationError.invalidParams("Please provide a valid clientId in constructor");
56
57
  if (options.enableLogging) log.enableAll();else log.setLevel("error");
@@ -251,6 +252,7 @@ class Web3AuthNoModal extends SafeEventEmitter {
251
252
  await this.setState({
252
253
  primaryConnectorName: null,
253
254
  cachedConnector: null,
255
+ cachedConnectorNamespace: null,
254
256
  currentChainId: null,
255
257
  idToken: null,
256
258
  accessToken: null,
@@ -797,7 +799,9 @@ class Web3AuthNoModal extends SafeEventEmitter {
797
799
  });
798
800
 
799
801
  // sync chainId
800
- this.commonJRPCProvider.on("chainChanged", async chainId => this.setCurrentChain(chainId));
802
+ this.commonJRPCProvider.on("chainChanged", async chainId => {
803
+ await this.setCurrentChain(chainId);
804
+ });
801
805
  }
802
806
  async setupConnector(connector) {
803
807
  this.subscribeToConnectorEvents(connector);
@@ -863,12 +867,19 @@ class Web3AuthNoModal extends SafeEventEmitter {
863
867
  injectedEvmConnector
864
868
  } = await import('./connectors/injected-evm-connector/index.js');
865
869
  const evmMipd = createMipd();
870
+ // `@metamask/connect-evm` SDK announces its own EIP-6963 provider (`io.metamask.mmc`) so
871
+ // it can be discovered by generic wallet pickers. We already register MetaMask via
872
+ // `metaMaskConnector`, so we must exclude the SDK-announced provider here; otherwise
873
+ // it is misclassified as an injected wallet and the modal shows MetaMask as installed,
874
+ // even when the user does not have the extension installed.
875
+ const isNonSdkAnnouncedProvider = providerDetail => providerDetail.info.rdns !== METAMASK_ERC_6963_PROVIDER_RDNS;
866
876
  // subscribe to new injected connectors
867
877
  evmMipd.subscribe(providerDetails => {
868
- const newConnectors = providerDetails.map(providerDetail => injectedEvmConnector(providerDetail)(config));
878
+ const filteredProviderDetails = providerDetails.filter(isNonSdkAnnouncedProvider);
879
+ const newConnectors = filteredProviderDetails.map(providerDetail => injectedEvmConnector(providerDetail)(config));
869
880
  this.setConnectors(newConnectors);
870
881
  });
871
- connectorFns.push(...evmMipd.getProviders().map(injectedEvmConnector));
882
+ connectorFns.push(...evmMipd.getProviders().filter(isNonSdkAnnouncedProvider).map(injectedEvmConnector));
872
883
  }
873
884
  }
874
885
 
@@ -1003,7 +1014,7 @@ class Web3AuthNoModal extends SafeEventEmitter {
1003
1014
  await this.setState({
1004
1015
  primaryConnectorName: data.connectorName
1005
1016
  });
1006
- this.cacheWallet(data.connectorName);
1017
+ this.cacheWallet(data.connectorName, data.connectorNamespace);
1007
1018
  const isConnectAndSign = this.coreOptions.initialAuthenticationMode === CONNECTOR_INITIAL_AUTHENTICATION_MODE.CONNECT_AND_SIGN;
1008
1019
  const pendingUserConsent = this.consentRequired && !this.state.hasUserConsent;
1009
1020
  if (pendingUserConsent && !isConnectAndSign) {
@@ -1018,7 +1029,6 @@ class Web3AuthNoModal extends SafeEventEmitter {
1018
1029
  if (this.status !== CONNECTOR_STATUS.CONSENT_REQUIRING && this.status !== CONNECTOR_STATUS.AUTHORIZED) {
1019
1030
  this.status = CONNECTOR_STATUS.CONNECTED;
1020
1031
  }
1021
- log.debug("connected", this.status, this.primaryConnectorName);
1022
1032
  // Defer plugin connection until consent is accepted; otherwise plugins would start before the consent step completes.
1023
1033
  // `completeConsentAcceptance` connects the plugins once the user accepts the consent.
1024
1034
  if (!pendingUserConsent) {
@@ -1136,7 +1146,14 @@ class Web3AuthNoModal extends SafeEventEmitter {
1136
1146
  // External wallets can resolve to a different active chain than the requested one,
1137
1147
  // so let connector-reported chain updates reconcile Web3Auth state after connect.
1138
1148
  if (typeof (data === null || data === void 0 ? void 0 : data.data) === "object" && (data === null || data === void 0 ? void 0 : data.data) !== null && "chainId" in data.data && typeof data.data.chainId === "string") {
1149
+ const previousChain = this.currentChain;
1139
1150
  await this.setCurrentChain(data.data.chainId);
1151
+ const currentChain = this.currentChain;
1152
+ const connectorEthereumProvider = connector.provider;
1153
+ if ((previousChain === null || previousChain === void 0 ? void 0 : previousChain.chainNamespace) !== (currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) && (currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.EIP155 && connectorEthereumProvider) {
1154
+ // from sol -> evm namespace switch, we need to re-create AccountAbstractionProvider
1155
+ await this.bindPrimaryEthereumSigningProxy(connectorEthereumProvider, connector.name);
1156
+ }
1140
1157
  }
1141
1158
  log.debug("connector data updated", data);
1142
1159
  this.emit(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, data);
@@ -1191,7 +1208,7 @@ class Web3AuthNoModal extends SafeEventEmitter {
1191
1208
  }
1192
1209
  checkIfAutoConnect(connector) {
1193
1210
  var _this$currentChain3;
1194
- let autoConnect = this.cachedConnector === connector.name;
1211
+ let autoConnect = this.cachedConnector === connector.name && this.state.cachedConnectorNamespace === connector.connectorNamespace;
1195
1212
  if (autoConnect && (_this$currentChain3 = this.currentChain) !== null && _this$currentChain3 !== void 0 && _this$currentChain3.chainNamespace) {
1196
1213
  if (connector.connectorNamespace === CONNECTOR_NAMESPACES.MULTICHAIN) autoConnect = true;else autoConnect = connector.connectorNamespace === this.currentChain.chainNamespace;
1197
1214
  }
@@ -1205,10 +1222,16 @@ class Web3AuthNoModal extends SafeEventEmitter {
1205
1222
  getInitialChainIdForConnector(connector) {
1206
1223
  var _initialChain;
1207
1224
  let initialChain = this.currentChain;
1208
- if (((_initialChain = initialChain) === null || _initialChain === void 0 ? void 0 : _initialChain.chainNamespace) !== connector.connectorNamespace && connector.connectorNamespace !== CONNECTOR_NAMESPACES.MULTICHAIN) {
1225
+ const defaultChainId = this.coreOptions.defaultChainId;
1226
+ const isMultiChainConnector = connector.connectorNamespace === CONNECTOR_NAMESPACES.MULTICHAIN;
1227
+
1228
+ // if the connector is a multi-chain connector and a default chain id is set, use the default chain id
1229
+ if (isMultiChainConnector && defaultChainId) {
1230
+ initialChain = this.coreOptions.chains.find(chain => chain.chainId === defaultChainId) || this.currentChain;
1231
+ } else if (((_initialChain = initialChain) === null || _initialChain === void 0 ? void 0 : _initialChain.chainNamespace) !== connector.connectorNamespace && connector.connectorNamespace !== CONNECTOR_NAMESPACES.MULTICHAIN) {
1209
1232
  initialChain = this.coreOptions.chains.find(x => x.chainNamespace === connector.connectorNamespace);
1210
- if (!initialChain) throw WalletInitializationError.invalidParams(`No chain found for ${connector.connectorNamespace}`);
1211
1233
  }
1234
+ if (!initialChain) throw WalletInitializationError.invalidParams(`No chain found for ${connector.connectorNamespace}`);
1212
1235
  return initialChain;
1213
1236
  }
1214
1237
  async completeConsentAcceptance() {
@@ -1394,7 +1417,8 @@ class Web3AuthNoModal extends SafeEventEmitter {
1394
1417
  return {
1395
1418
  ethereumProvider: connectedWallet.signingProvider,
1396
1419
  solanaWallet: (_connectedWallet$sola = connectedWallet.solanaWallet) !== null && _connectedWallet$sola !== void 0 ? _connectedWallet$sola : null,
1397
- connectorName: connectedWallet.connector.name
1420
+ connectorName: connectedWallet.connector.name,
1421
+ connectorNamespace: connectedWallet.connector.connectorNamespace
1398
1422
  };
1399
1423
  }
1400
1424
  buildImmediateConnectedWalletConnectorState(params) {
@@ -1532,11 +1556,7 @@ class Web3AuthNoModal extends SafeEventEmitter {
1532
1556
  if (!connection) {
1533
1557
  throw WalletLoginError.connectionError("Failed to resolve the active connection after switching accounts.");
1534
1558
  }
1535
- this.emit(CONNECTOR_EVENTS.CONNECTION_UPDATED, {
1536
- ethereumProvider: connection.ethereumProvider,
1537
- solanaWallet: connection.solanaWallet,
1538
- connectorName: connection.connectorName
1539
- });
1559
+ this.emit(CONNECTOR_EVENTS.CONNECTION_UPDATED, connection);
1540
1560
  }
1541
1561
  isActiveConnectorEventSource(connector) {
1542
1562
  if (!this.primaryConnectorName) return true;
@@ -1619,9 +1639,10 @@ class Web3AuthNoModal extends SafeEventEmitter {
1619
1639
  log.debug("Failed to cache connected linked wallet connector", error);
1620
1640
  }
1621
1641
  }
1622
- async cacheWallet(walletName) {
1642
+ async cacheWallet(walletName, connectorNamespace) {
1623
1643
  await this.setState({
1624
- cachedConnector: walletName
1644
+ cachedConnector: walletName,
1645
+ cachedConnectorNamespace: connectorNamespace
1625
1646
  });
1626
1647
  }
1627
1648
  async setCurrentChain(chainId) {
@@ -1657,9 +1678,11 @@ class Web3AuthNoModal extends SafeEventEmitter {
1657
1678
  });
1658
1679
  }
1659
1680
  async bindPrimaryEthereumSigningProxy(ethereumProvider, connectorName) {
1660
- var _this$currentChain5, _accountAbstractionCo;
1681
+ var _this$primaryConnecto2, _this$currentChain5, _accountAbstractionCo;
1661
1682
  if (!this.commonJRPCProvider) throw WalletInitializationError.notFound(`CommonJrpcProvider not found`);
1662
- let finalProvider = (ethereumProvider === null || ethereumProvider === void 0 ? void 0 : ethereumProvider.provider) || ethereumProvider;
1683
+ const primaryConnectorProvider = connectorName === this.primaryConnectorName ? (_this$primaryConnecto2 = this.primaryConnector) === null || _this$primaryConnecto2 === void 0 ? void 0 : _this$primaryConnecto2.provider : null;
1684
+ const baseEthereumProvider = ethereumProvider === this.commonJRPCProvider || ethereumProvider === this.aaProvider ? primaryConnectorProvider !== null && primaryConnectorProvider !== void 0 ? primaryConnectorProvider : ethereumProvider : ethereumProvider;
1685
+ let finalProvider = (baseEthereumProvider === null || baseEthereumProvider === void 0 ? void 0 : baseEthereumProvider.provider) || baseEthereumProvider;
1663
1686
  const {
1664
1687
  accountAbstractionConfig
1665
1688
  } = this.coreOptions;
@@ -1676,7 +1699,7 @@ class Web3AuthNoModal extends SafeEventEmitter {
1676
1699
  accountAbstractionProvider,
1677
1700
  toEoaProvider
1678
1701
  } = await import('./providers/account-abstraction-provider/index.js');
1679
- const eoaProvider = connectorName === WALLET_CONNECTORS.AUTH ? await toEoaProvider(ethereumProvider) : ethereumProvider;
1702
+ const eoaProvider = connectorName === WALLET_CONNECTORS.AUTH ? await toEoaProvider(baseEthereumProvider) : baseEthereumProvider;
1680
1703
  const aaChainIds = new Set((accountAbstractionConfig === null || accountAbstractionConfig === void 0 || (_accountAbstractionCo2 = accountAbstractionConfig.chains) === null || _accountAbstractionCo2 === void 0 ? void 0 : _accountAbstractionCo2.map(chain => chain.chainId)) || []);
1681
1704
  const aaProvider = await accountAbstractionProvider({
1682
1705
  accountAbstractionConfig,
@@ -54,7 +54,7 @@ class AccountAbstractionProvider extends BaseProvider {
54
54
  });
55
55
  }
56
56
  async setupProvider(eoaProvider) {
57
- var _bundlerConfig$transp;
57
+ var _ref, _bundlerConfig$transp;
58
58
  const currentChain = this.currentChain;
59
59
  if (!currentChain) {
60
60
  throw WalletInitializationError.invalidProviderConfigError(`AA chain config not found for chain ${this.chainId}`);
@@ -97,7 +97,14 @@ class AccountAbstractionProvider extends BaseProvider {
97
97
  chain,
98
98
  transport: http(currentChain.rpcTarget)
99
99
  });
100
- const [eoaAddress] = await eoaProvider.request({
100
+ // Firstly, try to get the accounts from the existing connected provider with `eth_accounts` method.
101
+ // We don't wanna do `eth_requestAccounts` method here, coz if the wallet is already connected, it will trigger chainChanged event and unintentionally update the AaProvider re-bind and
102
+ // re-bind run this again, so we will end up in infinite loop.
103
+ const existingAccounts = (_ref = await eoaProvider.request({
104
+ method: METHOD_TYPES.GET_ACCOUNTS
105
+ })) !== null && _ref !== void 0 ? _ref : [];
106
+ // only if the existing accounts are not found (that means wallet isn't connected), then we will trigger `eth_requestAccounts` method to get the accounts.
107
+ const [eoaAddress] = existingAccounts.length > 0 ? existingAccounts : await eoaProvider.request({
101
108
  method: METHOD_TYPES.ETH_REQUEST_ACCOUNTS
102
109
  });
103
110
  const walletClient = createWalletClient({
@@ -162,6 +162,14 @@ function useWeb3AuthInnerContextValue({
162
162
  setChainId(web3Auth.currentChainId);
163
163
  setChainNamespace((_web3Auth$currentChai1 = (_web3Auth$currentChai10 = web3Auth.currentChain) === null || _web3Auth$currentChai10 === void 0 ? void 0 : _web3Auth$currentChai10.chainNamespace) !== null && _web3Auth$currentChai1 !== void 0 ? _web3Auth$currentChai1 : null);
164
164
  };
165
+ const connectorDataUpdatedListener = data => {
166
+ const updatedData = data.data;
167
+ if (updatedData.chainId) {
168
+ var _web3Auth$currentChai11;
169
+ setChainId(updatedData.chainId);
170
+ setChainNamespace((_web3Auth$currentChai11 = web3Auth.currentChain) === null || _web3Auth$currentChai11 === void 0 ? void 0 : _web3Auth$currentChai11.chainNamespace);
171
+ }
172
+ };
165
173
  if (web3Auth) {
166
174
  web3Auth.on(CONNECTOR_EVENTS.NOT_READY, notReadyListener);
167
175
  web3Auth.on(CONNECTOR_EVENTS.READY, readyListener);
@@ -173,6 +181,7 @@ function useWeb3AuthInnerContextValue({
173
181
  web3Auth.on(CONNECTOR_EVENTS.REHYDRATION_ERROR, rehydrationErrorListener);
174
182
  web3Auth.on(CONNECTOR_EVENTS.MFA_ENABLED, mfaEnabledListener);
175
183
  web3Auth.on(CONNECTOR_EVENTS.CONNECTION_UPDATED, connectionUpdatedListener);
184
+ web3Auth.on(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, connectorDataUpdatedListener);
176
185
  if (web3Auth.loginMode === LOGIN_MODE.MODAL) {
177
186
  web3Auth.on(CONNECTOR_EVENTS.CONSENT_ACCEPTED, consentAcceptedListener);
178
187
  }
@@ -189,6 +198,7 @@ function useWeb3AuthInnerContextValue({
189
198
  web3Auth.removeListener(CONNECTOR_EVENTS.MFA_ENABLED, mfaEnabledListener);
190
199
  web3Auth.removeListener(CONNECTOR_EVENTS.AUTHORIZED, authorizedListener);
191
200
  web3Auth.removeListener(CONNECTOR_EVENTS.CONNECTION_UPDATED, connectionUpdatedListener);
201
+ web3Auth.removeListener(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, connectorDataUpdatedListener);
192
202
  if (web3Auth.loginMode === LOGIN_MODE.MODAL) {
193
203
  web3Auth.removeListener(CONNECTOR_EVENTS.CONSENT_ACCEPTED, consentAcceptedListener);
194
204
  }
@@ -7,6 +7,7 @@ import { useWeb3Auth } from '../hooks/useWeb3Auth.js';
7
7
  import { useChain } from '../hooks/useChain.js';
8
8
  import { CHAIN_NAMESPACES } from '@toruslabs/base-controllers';
9
9
  import { log } from '../../base/loglevel.js';
10
+ import { getCaipChainId } from '../../base/utils.js';
10
11
 
11
12
  const _excluded = ["children"];
12
13
  const DEVNET_ENDPOINT = "https://api.devnet.solana.com";
@@ -36,13 +37,29 @@ function makePlaceholder(rpc) {
36
37
  });
37
38
  }
38
39
  function dispose(client) {
39
- void client.actions.disconnectWallet().catch(() => {});
40
40
  client.destroy();
41
41
  }
42
+ function resolveSolanaChain(web3Auth, connection) {
43
+ var _web3Auth$coreOptions3;
44
+ const currentChain = web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.currentChain;
45
+ if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.SOLANA) {
46
+ return currentChain;
47
+ }
48
+ const connectedScope = connection !== null && connection !== void 0 && connection.solanaWallet && "scope" in connection.solanaWallet && typeof connection.solanaWallet.scope === "string" ? connection.solanaWallet.scope : null;
49
+ if (connectedScope) {
50
+ var _web3Auth$coreOptions2;
51
+ const connectedChain = web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions2 = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions2 === void 0 ? void 0 : _web3Auth$coreOptions2.find(chain => {
52
+ return chain.chainNamespace === CHAIN_NAMESPACES.SOLANA && getCaipChainId(chain) === connectedScope;
53
+ });
54
+ if (connectedChain) return connectedChain;
55
+ }
56
+ return (web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions3 = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions3 === void 0 ? void 0 : _web3Auth$coreOptions3.find(chain => chain.chainNamespace === CHAIN_NAMESPACES.SOLANA)) || null;
57
+ }
42
58
 
43
59
  /**
44
- * Builds the SolanaClient for Framework Kit React hooks: placeholder when idle, Web3Auth-backed when
45
- * connected on Solana. Ref + state so React re-renders on swap and effects dispose the right instance.
60
+ * Builds the SolanaClient for Framework Kit React hooks.
61
+ * For multichain wallets, keep the Solana client warm across namespace switches so
62
+ * switching back to Solana can reuse the existing wallet session.
46
63
  */
47
64
  function useFrameworkKitSolanaClient() {
48
65
  const {
@@ -55,12 +72,13 @@ function useFrameworkKitSolanaClient() {
55
72
  chainId,
56
73
  chainNamespace
57
74
  } = useChain();
58
- const ref = useRef(null);
75
+ const solClientRef = useRef(null);
76
+ const connectedClientRef = useRef(null);
59
77
  const [client, setClient] = useState(() => {
60
78
  const c = makePlaceholder({
61
79
  rpcTarget: DEVNET_ENDPOINT
62
80
  });
63
- ref.current = c;
81
+ solClientRef.current = c;
64
82
  return c;
65
83
  });
66
84
  useEffect(() => {
@@ -69,54 +87,61 @@ function useFrameworkKitSolanaClient() {
69
87
  });
70
88
  }, [isInitialized, web3Auth]);
71
89
  useEffect(() => () => {
72
- const c = ref.current;
73
- if (c) {
74
- dispose(c);
75
- ref.current = null;
90
+ const connectedClient = connectedClientRef.current;
91
+ const currentClient = solClientRef.current;
92
+ if (currentClient) {
93
+ dispose(currentClient);
94
+ solClientRef.current = null;
95
+ }
96
+ if (connectedClient && connectedClient !== currentClient) {
97
+ dispose(connectedClient);
76
98
  }
99
+ connectedClientRef.current = null;
77
100
  }, []);
78
101
  useEffect(() => {
79
102
  let stale = false;
80
- const adopt = next => {
103
+ const adopt = nextClient => {
81
104
  if (stale) {
82
- dispose(next);
105
+ dispose(nextClient);
83
106
  return;
84
107
  }
85
- const prev = ref.current;
86
- if (prev === next) return;
87
- if (prev) dispose(prev);
88
- ref.current = next;
89
- setClient(next);
108
+ const prevClient = solClientRef.current;
109
+ if (prevClient === nextClient) return;
110
+ if (prevClient) dispose(prevClient);
111
+ solClientRef.current = nextClient;
112
+ setClient(nextClient);
90
113
  };
91
- (async _web3Auth$currentChai => {
114
+ (async () => {
92
115
  const rpc = placeholderRpc(isInitialized, web3Auth);
93
- const solanaWallet = connection === null || connection === void 0 ? void 0 : connection.solanaWallet;
94
- const onSolana = isConnected && Boolean(solanaWallet) && chainNamespace === CHAIN_NAMESPACES.SOLANA && (web3Auth === null || web3Auth === void 0 || (_web3Auth$currentChai = web3Auth.currentChain) === null || _web3Auth$currentChai === void 0 ? void 0 : _web3Auth$currentChai.chainNamespace) === CHAIN_NAMESPACES.SOLANA;
95
- if (!onSolana) {
96
- adopt(makePlaceholder(rpc));
97
- return;
98
- }
99
116
  const conn = connection;
100
- if (!conn || !solanaWallet) {
117
+ const currentChain = web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.currentChain;
118
+ if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) !== CHAIN_NAMESPACES.SOLANA) {
101
119
  adopt(makePlaceholder(rpc));
102
120
  return;
103
121
  }
104
-
105
- // only reconnect for the primary connector
106
- if (conn.connectorName !== (web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.primaryConnectorName)) {
122
+ const preferredSolanaChain = resolveSolanaChain(web3Auth, conn);
123
+ const shouldKeepSolanaClient = isConnected && Boolean(conn === null || conn === void 0 ? void 0 : conn.solanaWallet) && Boolean(preferredSolanaChain) &&
124
+ // only manage the client for the primary connector
125
+ (conn === null || conn === void 0 ? void 0 : conn.connectorName) === (web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.primaryConnectorName);
126
+ if (!shouldKeepSolanaClient) {
127
+ const connectedClient = connectedClientRef.current;
128
+ connectedClientRef.current = null;
129
+ if (connectedClient) {
130
+ dispose(connectedClient);
131
+ }
107
132
  adopt(makePlaceholder(rpc));
108
133
  return;
109
134
  }
110
135
  try {
111
136
  const solanaWalletId = "wallet-standard:" + conn.connectorName;
112
- const connector = createWalletStandardConnector(solanaWallet, {
137
+ const connector = createWalletStandardConnector(conn.solanaWallet, {
113
138
  id: solanaWalletId,
114
139
  name: conn.connectorName
115
140
  });
116
141
  const {
117
142
  rpcTarget,
118
143
  wsTarget
119
- } = web3Auth.currentChain;
144
+ } = preferredSolanaChain;
120
145
  const wired = createClient({
121
146
  endpoint: rpcTarget,
122
147
  websocketEndpoint: wsTarget,
@@ -129,7 +154,16 @@ function useFrameworkKitSolanaClient() {
129
154
  dispose(wired);
130
155
  return;
131
156
  }
132
- adopt(wired);
157
+ const prevConnectedClient = connectedClientRef.current;
158
+ connectedClientRef.current = wired;
159
+ if (chainNamespace === CHAIN_NAMESPACES.SOLANA && (currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.SOLANA) {
160
+ adopt(wired);
161
+ } else {
162
+ adopt(makePlaceholder(rpc));
163
+ }
164
+ if (prevConnectedClient && prevConnectedClient !== wired) {
165
+ dispose(prevConnectedClient);
166
+ }
133
167
  } catch (e) {
134
168
  log.error("Failed to create or connect Solana client", e);
135
169
  adopt(makePlaceholder(rpc));
@@ -1,24 +1,36 @@
1
1
  import { createWalletStandardConnector, createClient } from '@solana/client';
2
- import { defineComponent, ref, provide, watch, h, Fragment } from 'vue';
2
+ import { defineComponent, ref, provide, watch, onBeforeUnmount, h, Fragment } from 'vue';
3
3
  import { CHAIN_NAMESPACES } from '@toruslabs/base-controllers';
4
4
  import { SOLANA_CLIENT_KEY } from './constants.js';
5
5
  import { useWeb3Auth } from '../composables/useWeb3Auth.js';
6
6
  import { useChain } from '../composables/useChain.js';
7
7
  import { log } from '../../base/loglevel.js';
8
+ import { getCaipChainId } from '../../base/utils.js';
8
9
 
9
10
  const disposeClient = async client => {
10
- try {
11
- await client.actions.disconnectWallet();
12
- } catch (e) {
13
- log.warn("Solana client disconnect", e);
14
- }
15
11
  client.destroy();
16
12
  };
13
+ const resolveSolanaChain = (web3Auth, connection) => {
14
+ var _web3Auth$coreOptions2;
15
+ const currentChain = web3Auth === null || web3Auth === void 0 ? void 0 : web3Auth.currentChain;
16
+ if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.SOLANA) {
17
+ return currentChain;
18
+ }
19
+ const connectedScope = connection !== null && connection !== void 0 && connection.solanaWallet && "scope" in connection.solanaWallet && typeof connection.solanaWallet.scope === "string" ? connection.solanaWallet.scope : null;
20
+ if (connectedScope) {
21
+ var _web3Auth$coreOptions;
22
+ const connectedChain = web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions === void 0 ? void 0 : _web3Auth$coreOptions.find(chain => {
23
+ return chain.chainNamespace === CHAIN_NAMESPACES.SOLANA && getCaipChainId(chain) === connectedScope;
24
+ });
25
+ if (connectedChain) return connectedChain;
26
+ }
27
+ return (web3Auth === null || web3Auth === void 0 || (_web3Auth$coreOptions2 = web3Auth.coreOptions.chains) === null || _web3Auth$coreOptions2 === void 0 ? void 0 : _web3Auth$coreOptions2.find(chain => chain.chainNamespace === CHAIN_NAMESPACES.SOLANA)) || null;
28
+ };
17
29
 
18
30
  /**
19
31
  * Syncs Web3Auth Solana connection with Framework Kit client.
20
- * When user is connected via Web3Auth and current chain is Solana, creates a Framework Kit client
21
- * with Web3Auth as the wallet connector and connects it (same pattern as Wagmi provider).
32
+ * For multichain wallets, keep the Solana client warm across namespace switches so
33
+ * switching back to Solana can reuse the existing wallet session.
22
34
  */
23
35
  const SolanaProvider = defineComponent({
24
36
  name: "SolanaProvider",
@@ -34,6 +46,8 @@ const SolanaProvider = defineComponent({
34
46
  chainId
35
47
  } = useChain();
36
48
  const clientRef = ref(null);
49
+ let connectedClient = null;
50
+ // let connectedClientKey: string | null = null;
37
51
  // Holds the token for the newest requested sync run. Older async runs compare against it
38
52
  // before publishing results so a slower reconnect cannot overwrite a newer chain/account update.
39
53
  let activeSyncToken = null;
@@ -49,21 +63,26 @@ const SolanaProvider = defineComponent({
49
63
  const newIsConnected = isConnected.value;
50
64
  const newConnection = connection.value;
51
65
  const currentChain = (_web3Auth$value = web3Auth.value) === null || _web3Auth$value === void 0 ? void 0 : _web3Auth$value.currentChain;
52
- if (!newIsConnected || !(newConnection !== null && newConnection !== void 0 && newConnection.solanaWallet) || (currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) !== CHAIN_NAMESPACES.SOLANA ||
53
- // only reconnect for the primary connector
54
- newConnection.connectorName !== ((_web3Auth$value2 = web3Auth.value) === null || _web3Auth$value2 === void 0 ? void 0 : _web3Auth$value2.primaryConnectorName)) {
55
- const prevClient = clientRef.value;
66
+ if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) !== CHAIN_NAMESPACES.SOLANA) {
67
+ // Mirror the React provider behavior: hide the live Solana client from injected
68
+ // consumers whenever Web3Auth is currently scoped to a non-Solana namespace.
56
69
  clientRef.value = null;
70
+ return;
71
+ }
72
+ const preferredSolanaChain = resolveSolanaChain(web3Auth.value, newConnection);
73
+ const shouldKeepSolanaClient = newIsConnected && Boolean(newConnection === null || newConnection === void 0 ? void 0 : newConnection.solanaWallet) && Boolean(preferredSolanaChain) &&
74
+ // only manage the client for the primary connector
75
+ (newConnection === null || newConnection === void 0 ? void 0 : newConnection.connectorName) === ((_web3Auth$value2 = web3Auth.value) === null || _web3Auth$value2 === void 0 ? void 0 : _web3Auth$value2.primaryConnectorName);
76
+ if (!shouldKeepSolanaClient) {
77
+ clientRef.value = null;
78
+ const prevClient = connectedClient;
79
+ connectedClient = null;
80
+ // connectedClientKey = null;
57
81
  if (prevClient) {
58
82
  await disposeClient(prevClient);
59
83
  }
60
84
  return;
61
85
  }
62
- const prevClient = clientRef.value;
63
- clientRef.value = null;
64
- if (prevClient) {
65
- await disposeClient(prevClient);
66
- }
67
86
  let client = null;
68
87
  try {
69
88
  // create a wallet standard connector from connected wallet
@@ -77,7 +96,7 @@ const SolanaProvider = defineComponent({
77
96
  const {
78
97
  rpcTarget,
79
98
  wsTarget
80
- } = currentChain;
99
+ } = preferredSolanaChain;
81
100
  client = createClient({
82
101
  endpoint: rpcTarget,
83
102
  websocketEndpoint: wsTarget,
@@ -93,7 +112,13 @@ const SolanaProvider = defineComponent({
93
112
  await disposeClient(client);
94
113
  return;
95
114
  }
96
- clientRef.value = client;
115
+ const prevClient = connectedClient;
116
+ connectedClient = client;
117
+ // connectedClientKey = nextClientKey;
118
+ clientRef.value = (currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.SOLANA ? client : null;
119
+ if (prevClient) {
120
+ await disposeClient(prevClient);
121
+ }
97
122
  } catch (err) {
98
123
  if (client) {
99
124
  await disposeClient(client);
@@ -112,6 +137,17 @@ const SolanaProvider = defineComponent({
112
137
  }, {
113
138
  immediate: true
114
139
  });
140
+ onBeforeUnmount(() => {
141
+ const publishedClient = clientRef.value;
142
+ clientRef.value = null;
143
+ const prevClient = connectedClient;
144
+ connectedClient = null;
145
+ if (prevClient) {
146
+ void disposeClient(prevClient);
147
+ } else if (publishedClient) {
148
+ void disposeClient(publishedClient);
149
+ }
150
+ });
115
151
  return () => {
116
152
  var _slots$default, _slots$default2;
117
153
  return h(Fragment, null, (_slots$default = (_slots$default2 = slots.default) === null || _slots$default2 === void 0 ? void 0 : _slots$default2.call(slots)) !== null && _slots$default !== void 0 ? _slots$default : []);
@@ -148,6 +148,14 @@ function useWeb3AuthInnerContextValue({
148
148
  chainId.value = web3Auth.value.currentChainId;
149
149
  chainNamespace.value = (_currentChain$chainNa4 = (_currentChain4 = web3Auth.value.currentChain) === null || _currentChain4 === void 0 ? void 0 : _currentChain4.chainNamespace) !== null && _currentChain$chainNa4 !== void 0 ? _currentChain$chainNa4 : null;
150
150
  };
151
+ const connectorDataUpdatedListener = data => {
152
+ const updatedData = data.data;
153
+ if (updatedData.chainId && chainId.value !== updatedData.chainId) {
154
+ var _currentChain5;
155
+ chainId.value = updatedData.chainId;
156
+ chainNamespace.value = (_currentChain5 = web3Auth.value.currentChain) === null || _currentChain5 === void 0 ? void 0 : _currentChain5.chainNamespace;
157
+ }
158
+ };
151
159
  if (prevWeb3Auth && newWeb3Auth !== prevWeb3Auth) {
152
160
  prevWeb3Auth.removeListener(CONNECTOR_EVENTS.NOT_READY, notReadyListener);
153
161
  prevWeb3Auth.removeListener(CONNECTOR_EVENTS.READY, readyListener);
@@ -159,6 +167,7 @@ function useWeb3AuthInnerContextValue({
159
167
  prevWeb3Auth.removeListener(CONNECTOR_EVENTS.REHYDRATION_ERROR, errorListener);
160
168
  prevWeb3Auth.removeListener(CONNECTOR_EVENTS.MFA_ENABLED, mfaEnabledListener);
161
169
  prevWeb3Auth.removeListener(CONNECTOR_EVENTS.CONNECTION_UPDATED, connectionUpdatedListener);
170
+ prevWeb3Auth.removeListener(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, connectorDataUpdatedListener);
162
171
  if (prevWeb3Auth.loginMode === LOGIN_MODE.MODAL) {
163
172
  prevWeb3Auth.removeListener(CONNECTOR_EVENTS.CONSENT_ACCEPTED, consentAcceptedListener);
164
173
  }
@@ -175,6 +184,7 @@ function useWeb3AuthInnerContextValue({
175
184
  newWeb3Auth.on(CONNECTOR_EVENTS.REHYDRATION_ERROR, errorListener);
176
185
  newWeb3Auth.on(CONNECTOR_EVENTS.MFA_ENABLED, mfaEnabledListener);
177
186
  newWeb3Auth.on(CONNECTOR_EVENTS.CONNECTION_UPDATED, connectionUpdatedListener);
187
+ newWeb3Auth.on(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, connectorDataUpdatedListener);
178
188
  if (newWeb3Auth.loginMode === LOGIN_MODE.MODAL) {
179
189
  newWeb3Auth.on(CONNECTOR_EVENTS.CONSENT_ACCEPTED, consentAcceptedListener);
180
190
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@web3auth/no-modal",
3
- "version": "11.1.0",
3
+ "version": "11.2.0",
4
4
  "description": "Multi chain wallet aggregator for web3Auth",
5
5
  "keywords": [
6
6
  "web3Auth/no-modal",
@@ -252,5 +252,5 @@
252
252
  "node": ">=22.x",
253
253
  "npm": ">=10.x"
254
254
  },
255
- "gitHead": "50c16e16f234a5934ce51f56e30b5ab48cad72ae"
255
+ "gitHead": "e2f5aedf569d05ffb73ce089bd9189c47cb163c6"
256
256
  }