@web3auth/no-modal 11.0.0-beta.1 → 11.0.0-beta.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.
@@ -1,6 +1,6 @@
1
1
  import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
2
2
  import _objectSpread from '@babel/runtime/helpers/objectSpread2';
3
- import { useMemo, createElement, useEffect, Fragment } from 'react';
3
+ import { useMemo, createElement, useRef, useEffect, Fragment } from 'react';
4
4
  import { defineChain } from 'viem';
5
5
  import { createConfig, WagmiProvider as WagmiProvider$1, webSocket, http, fallback, useConfig, useReconnect, useConnectionEffect } from 'wagmi';
6
6
  import { injected } from 'wagmi/connectors';
@@ -78,7 +78,8 @@ function Web3AuthWagmiProvider({
78
78
  }) {
79
79
  const {
80
80
  isConnected,
81
- connection
81
+ connection,
82
+ chainNamespace
82
83
  } = useWeb3Auth();
83
84
  const {
84
85
  disconnect
@@ -87,10 +88,17 @@ function Web3AuthWagmiProvider({
87
88
  const {
88
89
  mutate: reconnect
89
90
  } = useReconnect();
91
+ const suppressWagmiDisconnect = useRef(false);
92
+ const lastSyncedBinding = useRef({
93
+ provider: null,
94
+ connectorName: null
95
+ });
90
96
  useConnectionEffect({
91
97
  onDisconnect: async () => {
92
98
  log.info("Disconnected from wagmi");
93
- if (isConnected) await disconnect();
99
+ const isSuppressed = suppressWagmiDisconnect.current;
100
+ suppressWagmiDisconnect.current = false;
101
+ if (!isSuppressed && isConnected) await disconnect();
94
102
  const connector = getWeb3authConnector(wagmiConfig);
95
103
  // reset wagmi connector state if the provider handles disconnection because of the accountsChanged event
96
104
  // from the connected provider
@@ -101,20 +109,44 @@ function Web3AuthWagmiProvider({
101
109
  });
102
110
  useEffect(() => {
103
111
  (async () => {
104
- if (isConnected && connection !== null && connection !== void 0 && connection.ethereumProvider) {
112
+ const shouldBindToWagmi = isConnected && chainNamespace === CHAIN_NAMESPACES.EIP155 && Boolean(connection === null || connection === void 0 ? void 0 : connection.ethereumProvider);
113
+ if (shouldBindToWagmi) {
114
+ const hasSameBinding = lastSyncedBinding.current.provider === connection.ethereumProvider && lastSyncedBinding.current.connectorName === connection.connectorName;
115
+ if (hasSameBinding && wagmiConfig.state.status === "connected") {
116
+ return;
117
+ }
118
+ if (!hasSameBinding && getWeb3authConnector(wagmiConfig)) {
119
+ if (wagmiConfig.state.status === "connected") {
120
+ suppressWagmiDisconnect.current = true;
121
+ await disconnectWeb3AuthFromWagmi(wagmiConfig);
122
+ } else {
123
+ resetConnectorState(wagmiConfig);
124
+ }
125
+ }
105
126
  const connector = await setupConnector(connection.ethereumProvider, wagmiConfig);
106
127
  if (!connector) {
107
128
  throw new Error("Failed to setup connector");
108
129
  }
109
130
  await connectWeb3AuthWithWagmi(connector, wagmiConfig);
131
+ lastSyncedBinding.current = {
132
+ provider: connection.ethereumProvider,
133
+ connectorName: connection.connectorName
134
+ };
110
135
  reconnect();
111
- } else if (!isConnected) {
136
+ } else {
137
+ lastSyncedBinding.current = {
138
+ provider: null,
139
+ connectorName: null
140
+ };
112
141
  if (wagmiConfig.state.status === "connected") {
142
+ suppressWagmiDisconnect.current = true;
113
143
  await disconnectWeb3AuthFromWagmi(wagmiConfig);
144
+ } else if (getWeb3authConnector(wagmiConfig)) {
145
+ resetConnectorState(wagmiConfig);
114
146
  }
115
147
  }
116
148
  })();
117
- }, [isConnected, wagmiConfig, connection, reconnect]);
149
+ }, [chainNamespace, connection, isConnected, reconnect, wagmiConfig]);
118
150
  return createElement(Fragment, null, children);
119
151
  }
120
152
  function WagmiProvider(_ref) {
@@ -3,6 +3,7 @@ import { defineComponent, ref, provide, watch, 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
+ import { useChain } from '../composables/useChain.js';
6
7
  import { log } from '../../base/loglevel.js';
7
8
 
8
9
  const disposeClient = async client => {
@@ -29,63 +30,85 @@ const SolanaProvider = defineComponent({
29
30
  connection,
30
31
  web3Auth
31
32
  } = useWeb3Auth();
33
+ const {
34
+ chainId
35
+ } = useChain();
32
36
  const clientRef = ref(null);
37
+ // Holds the token for the newest requested sync run. Older async runs compare against it
38
+ // before publishing results so a slower reconnect cannot overwrite a newer chain/account update.
39
+ let activeSyncToken = null;
33
40
 
34
41
  // provide the client to the app
35
42
  provide(SOLANA_CLIENT_KEY, clientRef);
36
-
37
- // watch for changes in the connection and chain namespace
38
- watch([isConnected, connection], async ([newIsConnected, newConnection]) => {
39
- var _web3Auth$value;
40
- if (!newIsConnected || !(newConnection !== null && newConnection !== void 0 && newConnection.solanaWallet)) {
41
- if (clientRef.value) {
42
- await disposeClient(clientRef.value);
43
- clientRef.value = null;
43
+ const syncClient = async () => {
44
+ var _web3Auth$value, _web3Auth$value2;
45
+ // Only the latest async, `syncing` run should be allowed to attach its client.
46
+ // A fresh Symbol gives each run a unique identity without relying on counters.
47
+ const syncToken = Symbol("solana-client-sync");
48
+ activeSyncToken = syncToken;
49
+ const newIsConnected = isConnected.value;
50
+ const newConnection = connection.value;
51
+ 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;
56
+ clientRef.value = null;
57
+ if (prevClient) {
58
+ await disposeClient(prevClient);
44
59
  }
45
60
  return;
46
61
  }
47
- const currentChain = web3Auth.value.currentChain;
48
- let chainConfig;
49
- if ((currentChain === null || currentChain === void 0 ? void 0 : currentChain.chainNamespace) === CHAIN_NAMESPACES.SOLANA) {
50
- chainConfig = currentChain;
51
- } else {
52
- // use the 1st Solana chain if current chain is not solana
53
- chainConfig = web3Auth.value.coreOptions.chains.find(c => c.chainNamespace === CHAIN_NAMESPACES.SOLANA);
54
- if (!chainConfig) return;
55
- }
56
-
57
- // only reconnect for the primary connector
58
- if (newConnection.connectorName !== ((_web3Auth$value = web3Auth.value) === null || _web3Auth$value === void 0 ? void 0 : _web3Auth$value.primaryConnectorName)) return;
59
62
  const prevClient = clientRef.value;
63
+ clientRef.value = null;
64
+ if (prevClient) {
65
+ await disposeClient(prevClient);
66
+ }
67
+ let client = null;
60
68
  try {
61
69
  // create a wallet standard connector from connected wallet
62
- const solanaWalletId = "wallet-standard:" + connection.value.connectorName;
63
- const connector = createWalletStandardConnector(connection.value.solanaWallet, {
70
+ const solanaWalletId = "wallet-standard:" + newConnection.connectorName;
71
+ const connector = createWalletStandardConnector(newConnection.solanaWallet, {
64
72
  id: solanaWalletId,
65
- name: connection.value.connectorName
73
+ name: newConnection.connectorName
66
74
  });
67
75
 
68
76
  // create a solana client
69
77
  const {
70
78
  rpcTarget,
71
79
  wsTarget
72
- } = chainConfig;
73
- const client = createClient({
80
+ } = currentChain;
81
+ client = createClient({
74
82
  endpoint: rpcTarget,
75
83
  websocketEndpoint: wsTarget,
76
84
  walletConnectors: [connector]
77
85
  });
78
- clientRef.value = client;
79
- if (prevClient) await disposeClient(prevClient);
80
86
 
81
87
  // connect the client to the wallet
82
88
  await client.actions.connectWallet(solanaWalletId, {
83
89
  autoConnect: true
84
90
  });
91
+ // If another sync started while connectWallet was in flight, this client is stale.
92
+ if (activeSyncToken !== syncToken) {
93
+ await disposeClient(client);
94
+ return;
95
+ }
96
+ clientRef.value = client;
85
97
  } catch (err) {
98
+ if (client) {
99
+ await disposeClient(client);
100
+ }
86
101
  log.error("Failed to create or connect Solana client", err);
87
- clientRef.value = null;
102
+ // Only clear the shared ref when this failing run is still the newest one.
103
+ if (activeSyncToken === syncToken) {
104
+ clientRef.value = null;
105
+ }
88
106
  }
107
+ };
108
+
109
+ // watch for changes in the connection and active chain
110
+ watch([isConnected, connection, chainId], () => {
111
+ void syncClient();
89
112
  }, {
90
113
  immediate: true
91
114
  });
@@ -78,7 +78,8 @@ const Web3AuthWagmiProvider = defineComponent({
78
78
  setup() {
79
79
  const {
80
80
  isConnected,
81
- connection
81
+ connection,
82
+ chainNamespace
82
83
  } = useWeb3Auth();
83
84
  const {
84
85
  disconnect
@@ -87,11 +88,15 @@ const Web3AuthWagmiProvider = defineComponent({
87
88
  const {
88
89
  mutate: reconnect
89
90
  } = useReconnect();
90
- const lastSyncedWeb3AuthConnection = shallowRef(null);
91
+ const lastSyncedProvider = shallowRef(null);
92
+ const lastSyncedConnectorName = ref(null);
93
+ const suppressWagmiDisconnect = ref(false);
91
94
  useConnectionEffect({
92
95
  onDisconnect: async () => {
93
96
  log.info("Disconnected from wagmi");
94
- if (isConnected.value) await disconnect();
97
+ const isSuppressed = suppressWagmiDisconnect.value;
98
+ suppressWagmiDisconnect.value = false;
99
+ if (!isSuppressed && isConnected.value) await disconnect();
95
100
  const connector = getWeb3authConnector(wagmiConfig);
96
101
  // reset wagmi connector state if the provider handles disconnection because of the accountsChanged event
97
102
  // from the connected provider
@@ -100,30 +105,41 @@ const Web3AuthWagmiProvider = defineComponent({
100
105
  }
101
106
  }
102
107
  });
103
- watch([isConnected, connection], async () => {
108
+ watch([isConnected, connection, chainNamespace], async () => {
104
109
  var _newConnection$ethere;
105
110
  const newIsConnected = isConnected.value;
106
111
  const newConnection = connection.value;
107
112
  const newEth = (_newConnection$ethere = newConnection === null || newConnection === void 0 ? void 0 : newConnection.ethereumProvider) !== null && _newConnection$ethere !== void 0 ? _newConnection$ethere : null;
108
- if (newIsConnected && newConnection && newEth) {
109
- // Linked-account switches can reuse or replace the underlying wallet provider,
110
- // so key wagmi resyncs off the Web3Auth connection object instead of provider identity.
111
- if (lastSyncedWeb3AuthConnection.value !== newConnection) {
112
- if (getWeb3authConnector(wagmiConfig)) {
113
+ const shouldBindToWagmi = newIsConnected && chainNamespace.value === CHAIN_NAMESPACES.EIP155 && Boolean(newConnection && newEth);
114
+ if (shouldBindToWagmi && newConnection && newEth) {
115
+ const hasSameBinding = lastSyncedProvider.value === newEth && lastSyncedConnectorName.value === newConnection.connectorName;
116
+ if (hasSameBinding && wagmiConfig.state.status === "connected") {
117
+ return;
118
+ }
119
+ if (!hasSameBinding && getWeb3authConnector(wagmiConfig)) {
120
+ if (wagmiConfig.state.status === "connected") {
121
+ suppressWagmiDisconnect.value = true;
122
+ await disconnectWeb3AuthFromWagmi(wagmiConfig);
123
+ } else {
113
124
  resetConnectorState(wagmiConfig);
114
125
  }
115
- lastSyncedWeb3AuthConnection.value = newConnection;
116
- const connector = await setupConnector(newEth, wagmiConfig);
117
- if (!connector) {
118
- throw new Error("Failed to setup connector");
119
- }
120
- await connectWeb3AuthWithWagmi(connector, wagmiConfig);
121
- reconnect();
122
126
  }
123
- } else if (!newIsConnected) {
124
- lastSyncedWeb3AuthConnection.value = null;
127
+ const connector = await setupConnector(newEth, wagmiConfig);
128
+ if (!connector) {
129
+ throw new Error("Failed to setup connector");
130
+ }
131
+ await connectWeb3AuthWithWagmi(connector, wagmiConfig);
132
+ lastSyncedProvider.value = newEth;
133
+ lastSyncedConnectorName.value = newConnection.connectorName;
134
+ reconnect();
135
+ } else {
136
+ lastSyncedProvider.value = null;
137
+ lastSyncedConnectorName.value = null;
125
138
  if (wagmiConfig.state.status === "connected") {
139
+ suppressWagmiDisconnect.value = true;
126
140
  await disconnectWeb3AuthFromWagmi(wagmiConfig);
141
+ } else if (getWeb3authConnector(wagmiConfig)) {
142
+ resetConnectorState(wagmiConfig);
127
143
  }
128
144
  }
129
145
  }, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@web3auth/no-modal",
3
- "version": "11.0.0-beta.1",
3
+ "version": "11.0.0-beta.2",
4
4
  "description": "Multi chain wallet aggregator for web3Auth",
5
5
  "keywords": [
6
6
  "web3Auth/no-modal",
@@ -88,7 +88,7 @@
88
88
  "@walletconnect/types": "^2.23.9",
89
89
  "@walletconnect/utils": "^2.23.9",
90
90
  "@web3auth/auth": "^11.8.0",
91
- "@web3auth/ws-embed": "^6.0.0",
91
+ "@web3auth/ws-embed": "^6.0.4",
92
92
  "bignumber.js": "~9.3.1",
93
93
  "deepmerge": "^4.3.1",
94
94
  "ethers": "^6.16.0",
@@ -252,5 +252,5 @@
252
252
  "node": ">=22.x",
253
253
  "npm": ">=10.x"
254
254
  },
255
- "gitHead": "a15a4f552ee844c7b743f48f4b725c52b6b7316d"
255
+ "gitHead": "05577130ae9ced90ed412c1597681672074d8d2a"
256
256
  }