@web3auth/no-modal 11.0.0 → 11.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 (28) hide show
  1. package/dist/lib.cjs/base/analytics.js +7 -0
  2. package/dist/lib.cjs/base/utils.js +1 -1
  3. package/dist/lib.cjs/connectors/auth-connector/authConnector.js +5 -3
  4. package/dist/lib.cjs/connectors/base-evm-connector/baseEvmConnector.js +3 -2
  5. package/dist/lib.cjs/connectors/metamask-connector/metamaskConnector.js +59 -22
  6. package/dist/lib.cjs/connectors/wallet-connect-v2-connector/config.js +3 -0
  7. package/dist/lib.cjs/connectors/wallet-connect-v2-connector/index.js +1 -0
  8. package/dist/lib.cjs/index.js +1 -0
  9. package/dist/lib.cjs/noModal.js +27 -13
  10. package/dist/lib.cjs/providers/account-abstraction-provider/providers/AccountAbstractionProvider.js +12 -2
  11. package/dist/lib.cjs/providers/account-abstraction-provider/rpc/ethRpcMiddlewares.js +43 -1
  12. package/dist/lib.cjs/types/base/analytics.d.ts +6 -0
  13. package/dist/lib.cjs/types/base/connector/interfaces.d.ts +6 -2
  14. package/dist/lib.cjs/types/base/core/IWeb3Auth.d.ts +3 -2
  15. package/dist/lib.cjs/types/connectors/wallet-connect-v2-connector/config.d.ts +1 -0
  16. package/dist/lib.cjs/types/noModal.d.ts +1 -1
  17. package/dist/lib.esm/base/analytics.js +7 -0
  18. package/dist/lib.esm/base/utils.js +1 -1
  19. package/dist/lib.esm/connectors/auth-connector/authConnector.js +5 -3
  20. package/dist/lib.esm/connectors/base-evm-connector/baseEvmConnector.js +3 -2
  21. package/dist/lib.esm/connectors/metamask-connector/metamaskConnector.js +60 -23
  22. package/dist/lib.esm/connectors/wallet-connect-v2-connector/config.js +4 -1
  23. package/dist/lib.esm/connectors/wallet-connect-v2-connector/index.js +1 -1
  24. package/dist/lib.esm/index.js +1 -1
  25. package/dist/lib.esm/noModal.js +27 -13
  26. package/dist/lib.esm/providers/account-abstraction-provider/providers/AccountAbstractionProvider.js +12 -2
  27. package/dist/lib.esm/providers/account-abstraction-provider/rpc/ethRpcMiddlewares.js +9 -1
  28. package/package.json +2 -2
@@ -107,6 +107,13 @@ const ANALYTICS_EVENTS = {
107
107
  MFA_ENABLEMENT_FAILED: "MFA Enablement Failed",
108
108
  MFA_MANAGEMENT_SELECTED: "MFA Management Selected",
109
109
  MFA_MANAGEMENT_FAILED: "MFA Management Failed",
110
+ // Consent Flow
111
+ USER_CONSENT_STARTED: "User Consent Started",
112
+ USER_CONSENT_ACCEPTED: "User Consent Accepted",
113
+ USER_CONSENT_DECLINED: "User Consent Declined",
114
+ USER_CONSENT_ERRORED: "User Consent Errored",
115
+ TERMS_OF_SERVICE_CLICKED: "Terms of Service Clicked",
116
+ PRIVACY_POLICY_CLICKED: "Privacy Policy Clicked",
110
117
  // Login Modal
111
118
  LOGIN_MODAL_OPENED: "Login Modal Opened",
112
119
  LOGIN_MODAL_CLOSED: "Login Modal Closed",
@@ -145,7 +145,7 @@ const getWalletServicesAnalyticsProperties = walletServicesConfig => {
145
145
  ws_default_portfolio: walletServicesConfig === null || walletServicesConfig === void 0 || (_walletServicesConfig10 = walletServicesConfig.whiteLabel) === null || _walletServicesConfig10 === void 0 ? void 0 : _walletServicesConfig10.defaultPortfolio
146
146
  };
147
147
  };
148
- const sdkVersion = "11.0.0";
148
+ const sdkVersion = "11.0.2";
149
149
  const getErrorAnalyticsProperties = error => {
150
150
  try {
151
151
  const code = error instanceof index.Web3AuthError ? error.code : error === null || error === void 0 ? void 0 : error.code;
@@ -492,7 +492,7 @@ class AuthConnector extends baseConnector.BaseConnector {
492
492
  accessToken,
493
493
  idToken
494
494
  } = await this.getPrimaryAuthSession(params.authSessionTokens);
495
- const walletProof = await this.createWalletLinkingProof(params.connectorToLink);
495
+ const walletProof = await this.createWalletLinkingProof(params.connectorToLink, chainId);
496
496
  const authServerUrl = utils.citadelServerUrl(this.coreOptions.authBuildEnv);
497
497
  const result = await rest.makeAccountLinkingRequest(authServerUrl, accessToken, {
498
498
  idToken,
@@ -684,7 +684,7 @@ class AuthConnector extends baseConnector.BaseConnector {
684
684
  }
685
685
  throw errors.AccountLinkingError.requestFailed(`Unsupported chain namespace "${matchedAccount.chainNamespace}" for address "${address}".`);
686
686
  }
687
- async createWalletLinkingProof(connector) {
687
+ async createWalletLinkingProof(connector, chainId) {
688
688
  // Notify listeners that the linking wallet is about to be asked for a signature so the UI
689
689
  // (e.g. modal) can switch from a "connecting" loader to an "authorizing" prompt while the
690
690
  // user reviews the signature request inside their wallet. Emitted on the isolated wallet
@@ -692,11 +692,13 @@ class AuthConnector extends baseConnector.BaseConnector {
692
692
  connector.emit(constants.CONNECTOR_EVENTS.AUTHORIZING, {
693
693
  connector: connector.name
694
694
  });
695
+ // Reuse the caller's target chain so multichain wallets generate the linking
696
+ // proof for the same namespace they were connected for.
695
697
  const {
696
698
  challenge,
697
699
  signature,
698
700
  chainNamespace
699
- } = await connector.generateChallengeAndSign();
701
+ } = await connector.generateChallengeAndSign(undefined, undefined, chainId);
700
702
  const address = await this.getLinkingWalletAddress(connector, chainNamespace);
701
703
  if (chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155) {
702
704
  return {
@@ -3,6 +3,7 @@
3
3
  var baseControllers = require('@toruslabs/base-controllers');
4
4
  var metadataHelpers = require('@toruslabs/metadata-helpers');
5
5
  var wsEmbed = require('@web3auth/ws-embed');
6
+ var viem = require('viem');
6
7
  var siwe = require('viem/siwe');
7
8
  require('@babel/runtime/helpers/objectSpread2');
8
9
  require('@babel/runtime/helpers/defineProperty');
@@ -67,9 +68,9 @@ class BaseEvmConnector extends baseConnector.BaseConnector {
67
68
  } = currentChainConfig;
68
69
  const authServer = authServerUrl || utils.citadelServerUrl(this.coreOptions.authBuildEnv);
69
70
  const payload = {
70
- domain: window.location.origin,
71
+ domain: window.location.host,
71
72
  uri: window.location.href,
72
- address: accountsToUse[0],
73
+ address: viem.checksumAddress(accountsToUse[0]),
73
74
  chainId: parseInt(chainId, 16),
74
75
  version: "1",
75
76
  nonce: siwe.generateSiweNonce(),
@@ -140,7 +140,12 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
140
140
  this.disconnect();
141
141
  }
142
142
  },
143
- chainChanged: _chainId => {},
143
+ chainChanged: _chainId => {
144
+ // Keep Web3Auth state aligned with the wallet's actual EVM chain after connect/switch.
145
+ this.updateConnectorData({
146
+ chainId: _chainId
147
+ });
148
+ },
144
149
  connect: _result => {},
145
150
  disconnect: () => {
146
151
  if (this.connected) {
@@ -196,7 +201,7 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
196
201
  ethereumProvider: this.evmProvider,
197
202
  solanaWallet: this.solanaProvider
198
203
  });
199
- if (options.getAuthTokenInfo) await this.getAuthTokenInfo();
204
+ if (options.getAuthTokenInfo) await this.getAuthTokenInfo(options.chainId);
200
205
  } else if (coreStatus === "connected" || coreStatus === "loaded" || coreStatus === "disconnected" || coreStatus === "pending") {
201
206
  this.status = constants.CONNECTOR_STATUS.READY;
202
207
  this.emit(constants.CONNECTOR_EVENTS.READY, index.WALLET_CONNECTORS.METAMASK);
@@ -259,13 +264,9 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
259
264
  await evmConnectedPromise;
260
265
  }
261
266
  }
262
- // // Switch EVM chain if not connected to the right one (Solana chains are handled by the wallet-standard provider)
263
- // if (chainConfig.chainNamespace === CHAIN_NAMESPACES.EIP155) {
264
- // const currentChainId = this.evmClient!.getChainId();
265
- // if (currentChainId !== chainId) {
266
- // await this.switchChain(chainConfig, true);
267
- // }
268
- // }
267
+ // sync the chain state after connect
268
+ // metamask might not be connected to the requested chain, so we need to sync the chain state to/from Web3Auth state after connect.
269
+ await this.syncChainStateAfterConnect(chainConfig);
269
270
  // check if connected
270
271
  if (this.multichainClient.status !== "connected") {
271
272
  throw index$1.WalletLoginError.notConnectedError("Failed to connect with MetaMask wallet");
@@ -286,7 +287,7 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
286
287
  solanaWallet: this.solanaProvider
287
288
  });
288
289
  if (getAuthTokenInfo) {
289
- await this.getAuthTokenInfo();
290
+ await this.getAuthTokenInfo(chainId);
290
291
  }
291
292
  return {
292
293
  ethereumProvider: this.evmProvider,
@@ -336,13 +337,11 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
336
337
  connector: index.WALLET_CONNECTORS.METAMASK
337
338
  });
338
339
  }
339
- async getAuthTokenInfo() {
340
- var _this$evmProvider2, _this$coreOptions$cha;
340
+ async getAuthTokenInfo(chainId) {
341
341
  if (!this.canAuthorize) throw index$1.WalletLoginError.notConnectedError();
342
- // Determine the active chain: prefer Solana if no EVM provider, otherwise use EVM provider's chain
343
- const evmChainId = ((_this$evmProvider2 = this.evmProvider) === null || _this$evmProvider2 === void 0 ? void 0 : _this$evmProvider2.chainId) || ((_this$coreOptions$cha = this.coreOptions.chains.find(x => x.chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155)) === null || _this$coreOptions$cha === void 0 ? void 0 : _this$coreOptions$cha.chainId);
344
- const isSolanaOnly = !this.evmProvider && !!this.solanaProvider;
345
- const activeChainConfig = isSolanaOnly ? this.coreOptions.chains.find(x => x.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) : this.evmProvider ? this.coreOptions.chains.find(x => x.chainId === evmChainId) : undefined;
342
+ // In multichain sessions both providers can exist at the same time, so auth must
343
+ // follow the caller-selected chain instead of inferring from provider availability.
344
+ const activeChainConfig = this.resolveAuthChainConfig(chainId);
346
345
  if (!activeChainConfig) throw index$1.WalletLoginError.connectionError("Chain config is not available");
347
346
  const {
348
347
  chainNamespace
@@ -362,7 +361,7 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
362
361
  const {
363
362
  challenge,
364
363
  signature
365
- } = await this.generateChallengeAndSign(authServer, accounts);
364
+ } = await this.generateChallengeAndSign(authServer, accounts, activeChainConfig.chainId);
366
365
  return this.verifyAndAuthorize({
367
366
  chainNamespace,
368
367
  signedMessage: signature,
@@ -403,11 +402,8 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
403
402
  chainConfiguration
404
403
  });
405
404
  }
406
- async generateChallengeAndSign(authServerUrl, accounts) {
407
- var _this$evmProvider3, _this$coreOptions$cha2;
408
- const evmChainId = ((_this$evmProvider3 = this.evmProvider) === null || _this$evmProvider3 === void 0 ? void 0 : _this$evmProvider3.chainId) || ((_this$coreOptions$cha2 = this.coreOptions.chains.find(x => x.chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155)) === null || _this$coreOptions$cha2 === void 0 ? void 0 : _this$coreOptions$cha2.chainId);
409
- const isSolanaOnly = !this.evmProvider && !!this.solanaProvider;
410
- const activeChainConfig = isSolanaOnly ? this.coreOptions.chains.find(x => x.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) : this.evmProvider ? this.coreOptions.chains.find(x => x.chainId === evmChainId) : undefined;
405
+ async generateChallengeAndSign(authServerUrl, accounts, chainId) {
406
+ const activeChainConfig = this.resolveAuthChainConfig(chainId);
411
407
  if (!activeChainConfig) throw index$1.WalletLoginError.connectionError("Chain config is not available");
412
408
  const {
413
409
  chainNamespace
@@ -462,6 +458,47 @@ class MetaMaskConnector extends baseConnector.BaseConnector {
462
458
  }
463
459
  await this.initializationPromise;
464
460
  }
461
+ async syncChainStateAfterConnect(chainConfig) {
462
+ var _this$evmProvider2;
463
+ // EVM connectors can switch chains, so align the wallet with the requested chain
464
+ // before Web3Auth persists the active chain in controller state.
465
+ if (chainConfig.chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155 && ((_this$evmProvider2 = this.evmProvider) === null || _this$evmProvider2 === void 0 ? void 0 : _this$evmProvider2.chainId) !== chainConfig.chainId) {
466
+ await this.switchChain({
467
+ chainId: chainConfig.chainId
468
+ }, true);
469
+ } else if (chainConfig.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) {
470
+ // For solana case, metamask connect the first available scope in priority order: mainnet > devnet > testnet.
471
+ // So, if the user requested chain is different from the connected chain,
472
+ // we need to update the connector data with the connected chain id to keep the Web3Auth state aligned.
473
+ if ("scope" in this.solanaProvider && typeof this.solanaProvider.scope === "string") {
474
+ var _this$coreOptions$cha;
475
+ const connectedSolChain = this.solanaProvider.scope;
476
+ const connectedChainConfig = (_this$coreOptions$cha = this.coreOptions.chains) === null || _this$coreOptions$cha === void 0 ? void 0 : _this$coreOptions$cha.find(chain => {
477
+ return utils.getCaipChainId(chain) === connectedSolChain && chain.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA;
478
+ });
479
+ if (!connectedChainConfig) {
480
+ throw index$1.WalletLoginError.connectionError("Connected chain is not available in the chains config");
481
+ }
482
+ if (connectedChainConfig.chainId !== chainConfig.chainId) {
483
+ // since, switchChain is not supported for solana (in metamask connect),
484
+ // we will make use of the connector data to update the Web3Auth state.
485
+ this.updateConnectorData({
486
+ chainId: connectedChainConfig.chainId
487
+ });
488
+ }
489
+ }
490
+ }
491
+ }
492
+ resolveAuthChainConfig(chainId) {
493
+ var _this$evmProvider3, _this$coreOptions$cha2;
494
+ if (chainId) {
495
+ return this.coreOptions.chains.find(x => x.chainId === chainId);
496
+ }
497
+ const evmChainId = ((_this$evmProvider3 = this.evmProvider) === null || _this$evmProvider3 === void 0 ? void 0 : _this$evmProvider3.chainId) || ((_this$coreOptions$cha2 = this.coreOptions.chains.find(x => x.chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155)) === null || _this$coreOptions$cha2 === void 0 ? void 0 : _this$coreOptions$cha2.chainId);
498
+ const isSolanaOnly = !this.evmProvider && !!this.solanaProvider;
499
+ // Keep the old fallback for callers that do not pass a chainId yet.
500
+ return isSolanaOnly ? this.coreOptions.chains.find(x => x.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) : this.evmProvider ? this.coreOptions.chains.find(x => x.chainId === evmChainId) : undefined;
501
+ }
465
502
  }
466
503
  /**
467
504
  * Factory function to create a MetaMask connector
@@ -31,6 +31,8 @@ exports.DEFAULT_EIP155_METHODS = void 0;
31
31
  DEFAULT_EIP155_METHODS["ADD_ETHEREUM_CHAIN"] = "wallet_addEthereumChain";
32
32
  DEFAULT_EIP155_METHODS["SWITCH_ETHEREUM_CHAIN"] = "wallet_switchEthereumChain";
33
33
  })(exports.DEFAULT_EIP155_METHODS || (exports.DEFAULT_EIP155_METHODS = {}));
34
+ // methods that return `null` on success
35
+ const NULL_ON_SUCCESS_METHODS = [exports.DEFAULT_EIP155_METHODS.SWITCH_ETHEREUM_CHAIN, exports.DEFAULT_EIP155_METHODS.ADD_ETHEREUM_CHAIN];
34
36
  exports.DEFAULT_SOLANA_METHODS = void 0;
35
37
  (function (DEFAULT_SOLANA_METHODS) {
36
38
  DEFAULT_SOLANA_METHODS["SIGN_TRANSACTION"] = "solana_signTransaction";
@@ -123,6 +125,7 @@ const getWalletConnectV2Settings = async (chains, projectID) => {
123
125
  };
124
126
  };
125
127
 
128
+ exports.NULL_ON_SUCCESS_METHODS = NULL_ON_SUCCESS_METHODS;
126
129
  exports.getNamespacesFromChains = getNamespacesFromChains;
127
130
  exports.getRequiredNamespaces = getRequiredNamespaces;
128
131
  exports.getSupportedEventsByNamespace = getSupportedEventsByNamespace;
@@ -22,6 +22,7 @@ Object.defineProperty(exports, "DEFAULT_SOLANA_METHODS", {
22
22
  enumerable: true,
23
23
  get: function () { return config.DEFAULT_SOLANA_METHODS; }
24
24
  });
25
+ exports.NULL_ON_SUCCESS_METHODS = config.NULL_ON_SUCCESS_METHODS;
25
26
  exports.getNamespacesFromChains = config.getNamespacesFromChains;
26
27
  exports.getRequiredNamespaces = config.getRequiredNamespaces;
27
28
  exports.getSupportedEventsByNamespace = config.getSupportedEventsByNamespace;
@@ -165,6 +165,7 @@ Object.defineProperty(exports, "DEFAULT_SOLANA_METHODS", {
165
165
  enumerable: true,
166
166
  get: function () { return config.DEFAULT_SOLANA_METHODS; }
167
167
  });
168
+ exports.NULL_ON_SUCCESS_METHODS = config.NULL_ON_SUCCESS_METHODS;
168
169
  exports.getNamespacesFromChains = config.getNamespacesFromChains;
169
170
  exports.getRequiredNamespaces = config.getRequiredNamespaces;
170
171
  exports.getSupportedEventsByNamespace = config.getSupportedEventsByNamespace;
@@ -482,7 +482,9 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
482
482
  };
483
483
  try {
484
484
  this.analytics.track(analytics.ANALYTICS_EVENTS.IDENTITY_TOKEN_STARTED, trackData);
485
- const authTokenInfo = await this.primaryConnector.getAuthTokenInfo();
485
+ // Thread the controller's active chain into connector auth so multichain
486
+ // connectors sign for the same chain the app/session is currently using.
487
+ const authTokenInfo = await this.primaryConnector.getAuthTokenInfo(this.currentChainId);
486
488
  this.analytics.track(analytics.ANALYTICS_EVENTS.IDENTITY_TOKEN_COMPLETED, trackData);
487
489
  return {
488
490
  idToken: authTokenInfo.idToken
@@ -519,7 +521,9 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
519
521
  if (!(params !== null && params !== void 0 && params.connectorName)) {
520
522
  throw index.WalletInitializationError.invalidParams("connectorName is required when calling linkAccount on the no-modal SDK");
521
523
  }
522
- const chainId = this.resolveLinkAccountChainId(params.chainId);
524
+ const {
525
+ chainId
526
+ } = this.resolveLinkAccountChainConfig(params.chainId);
523
527
  const isolatedConnector = await this.createLinkingWalletConnector(params.connectorName, chainId);
524
528
  return this.linkAccountWithConnector(params.connectorName, chainId, isolatedConnector);
525
529
  }
@@ -911,11 +915,15 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
911
915
  }));
912
916
  this.setActiveWalletConnectorKey();
913
917
  this.connectionReconnected = data.reconnected;
918
+ const {
919
+ activeAccount,
920
+ currentChainId
921
+ } = this.state;
914
922
  // when ssr is enabled, we need to get the idToken from the connector.
915
923
  if (this.coreOptions.ssr) {
916
924
  try {
917
925
  var _data$accessToken, _data$refreshToken;
918
- const data = await connector.getAuthTokenInfo();
926
+ const data = await connector.getAuthTokenInfo(currentChainId);
919
927
  if (!data.idToken) throw index.WalletLoginError.connectionError("No idToken found");
920
928
  await this.setState({
921
929
  idToken: data.idToken,
@@ -932,10 +940,6 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
932
940
  }
933
941
  }
934
942
  // The following block only hits during rehydration
935
- const {
936
- activeAccount,
937
- currentChainId
938
- } = this.state;
939
943
  let rehydrateWithLinkedAccount = false;
940
944
  // for rehydration, if the active account is not the primary account, i.e. not `null`, create an isolated connector and connect to the chain
941
945
  if (activeAccount && !activeAccount.isPrimary && activeAccount.connector !== index$1.WALLET_CONNECTORS.AUTH) {
@@ -982,7 +986,7 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
982
986
  const pendingUserConsent = this.consentRequired && !this.state.hasUserConsent;
983
987
  if (pendingUserConsent && !isConnectAndSign) {
984
988
  this.status = constants.CONNECTOR_STATUS.CONSENT_REQUIRING;
985
- this.emit(constants.CONNECTOR_EVENTS.CONSENT_REQUIRING);
989
+ this.emit(constants.CONNECTOR_EVENTS.CONSENT_REQUIRING, _objectSpread({}, data));
986
990
  loglevel.log.debug("consent_requiring", this.status, this.primaryConnectorName);
987
991
  } else {
988
992
  // In CONNECT_AND_SIGN mode the AUTHORIZED handler can run before this point (e.g. when `ssr=true`
@@ -1102,7 +1106,13 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
1102
1106
  await this.clearCache();
1103
1107
  this.emit(constants.CONNECTOR_EVENTS.REHYDRATION_ERROR, error);
1104
1108
  });
1105
- connector.on(constants.CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, data => {
1109
+ connector.on(constants.CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, async data => {
1110
+ if (this.shouldIgnoreInactiveConnectorEvent(connector, constants.CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED)) return;
1111
+ // External wallets can resolve to a different active chain than the requested one,
1112
+ // so let connector-reported chain updates reconcile Web3Auth state after connect.
1113
+ 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") {
1114
+ await this.setCurrentChain(data.data.chainId);
1115
+ }
1106
1116
  loglevel.log.debug("connector data updated", data);
1107
1117
  this.emit(constants.CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, data);
1108
1118
  });
@@ -1139,7 +1149,9 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
1139
1149
  // if the user has not consented yet, we will ask for consent
1140
1150
  if (this.consentRequired && this.connection && !this.state.hasUserConsent) {
1141
1151
  this.status = constants.CONNECTOR_STATUS.CONSENT_REQUIRING;
1142
- this.emit(constants.CONNECTOR_EVENTS.CONSENT_REQUIRING);
1152
+ this.emit(constants.CONNECTOR_EVENTS.CONSENT_REQUIRING, {
1153
+ connectorName: data.connector
1154
+ });
1143
1155
  loglevel.log.debug("consent_requiring", this.status, this.primaryConnectorName);
1144
1156
  } else {
1145
1157
  this.status = constants.CONNECTOR_STATUS.AUTHORIZED;
@@ -1201,12 +1213,14 @@ class Web3AuthNoModal extends auth.SafeEventEmitter {
1201
1213
  reconnected: this.connectionReconnected
1202
1214
  });
1203
1215
  }
1204
- resolveLinkAccountChainId(chainId) {
1216
+ resolveLinkAccountChainConfig(chainId) {
1217
+ var _this$coreOptions$cha7;
1205
1218
  const finalChainId = chainId || this.state.currentChainId;
1206
- if (!finalChainId) {
1219
+ const chainConfig = (_this$coreOptions$cha7 = this.coreOptions.chains) === null || _this$coreOptions$cha7 === void 0 ? void 0 : _this$coreOptions$cha7.find(chain => chain.chainId === finalChainId);
1220
+ if (!chainConfig) {
1207
1221
  throw errors.AccountLinkingError.walletProofFailed("No chainId is available. Please specify chainId in LinkAccountParams or ensure the SDK has an active chain.");
1208
1222
  }
1209
- return finalChainId;
1223
+ return chainConfig;
1210
1224
  }
1211
1225
  /**
1212
1226
  * Resolves the chain ID for a switch account operation.
@@ -158,13 +158,23 @@ class AccountAbstractionProvider extends baseProvider.BaseProvider {
158
158
  });
159
159
  const provider = auth.providerFromEngineV2(engine);
160
160
  this.updateProviderEngineProxy(provider);
161
- eoaProvider.once("chainChanged", chainId => {
161
+ const chainChangedHandler = chainId => {
162
162
  this.update({
163
163
  chainId
164
164
  });
165
165
  this.setupChainSwitchMiddleware();
166
166
  this.emit("chainChanged", chainId);
167
- });
167
+ if (eoaProvider !== null && eoaProvider !== void 0 && eoaProvider.removeListener && typeof eoaProvider.removeListener === "function") {
168
+ eoaProvider.removeListener("chainChanged", chainChangedHandler);
169
+ }
170
+ };
171
+ if (eoaProvider !== null && eoaProvider !== void 0 && eoaProvider.once && typeof eoaProvider.once === "function") {
172
+ eoaProvider.once("chainChanged", chainChangedHandler);
173
+ } else {
174
+ // some providers like trust wallet does not have `once` method, so we use `on` instead
175
+ // and cleanup the listener after the event triggers once
176
+ eoaProvider.on("chainChanged", chainChangedHandler);
177
+ }
168
178
  }
169
179
  async updateAccount(_params) {
170
180
  throw auth.providerErrors.unsupportedMethod("updateAccount. Please call it on eoaProvider");
@@ -3,6 +3,41 @@
3
3
  var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
4
4
  var ethereumControllers = require('@toruslabs/ethereum-controllers');
5
5
  var auth = require('@web3auth/auth');
6
+ require('@babel/runtime/helpers/defineProperty');
7
+ require('@toruslabs/base-controllers');
8
+ require('@toruslabs/constants');
9
+ require('@toruslabs/http-helpers');
10
+ require('@toruslabs/secure-pub-sub');
11
+ require('@web3auth/ws-embed');
12
+ require('deepmerge');
13
+ require('@segment/analytics-next');
14
+ require('../../../base/loglevel.js');
15
+ require('@toruslabs/session-manager');
16
+ require('../../../base/errors/index.js');
17
+ require('../../../base/constants.js');
18
+ require('../../../base/wallet/index.js');
19
+ require('../../../base/connector/connectorStatus.js');
20
+ require('../../../base/connector/constants.js');
21
+ require('jwt-decode');
22
+ require('../../../base/plugin/errors.js');
23
+ require('../../../base/plugin/IPlugin.js');
24
+ require('@toruslabs/eccrypto');
25
+ require('@toruslabs/metadata-helpers');
26
+ require('../../../connectors/auth-connector/authSolanaWallet.js');
27
+ require('viem');
28
+ require('viem/siwe');
29
+ require('mipd');
30
+ require('@solana/wallet-standard-features');
31
+ require('@wallet-standard/app');
32
+ require('@wallet-standard/features');
33
+ require('@metamask/connect-evm');
34
+ require('@metamask/connect-multichain');
35
+ require('@metamask/connect-solana');
36
+ var config = require('../../../connectors/wallet-connect-v2-connector/config.js');
37
+ require('@walletconnect/sign-client');
38
+ require('@walletconnect/utils');
39
+ require('../../../connectors/wallet-connect-v2-connector/WalletConnectV2Provider.js');
40
+ require('../../../connectors/wallet-connect-v2-connector/wcSolanaWallet.js');
6
41
 
7
42
  async function createAaMiddleware({
8
43
  eoaProvider,
@@ -199,10 +234,17 @@ function providerAsMiddleware(provider) {
199
234
  return async ({
200
235
  request
201
236
  }) => {
202
- return provider.request({
237
+ const result = await provider.request({
203
238
  method: request.method,
204
239
  params: request.params
205
240
  });
241
+ if (result === undefined && config.NULL_ON_SUCCESS_METHODS.includes(request.method)) {
242
+ // For some RPC requests, such as `wallet_switchEthereumChain`, the standard rpc result is `null`.
243
+ // However, some wallet providers might return `undefined` instead and causing the JRPCEngineV2 to throw `Nothing ended the request` error.
244
+ // So, we handle this case by returning `null` instead, so that JRPCEngineV2 won't throw `Nothing ended the request` error
245
+ return null;
246
+ }
247
+ return result;
206
248
  };
207
249
  }
208
250
 
@@ -26,6 +26,12 @@ export declare const ANALYTICS_EVENTS: {
26
26
  MFA_ENABLEMENT_FAILED: string;
27
27
  MFA_MANAGEMENT_SELECTED: string;
28
28
  MFA_MANAGEMENT_FAILED: string;
29
+ USER_CONSENT_STARTED: string;
30
+ USER_CONSENT_ACCEPTED: string;
31
+ USER_CONSENT_DECLINED: string;
32
+ USER_CONSENT_ERRORED: string;
33
+ TERMS_OF_SERVICE_CLICKED: string;
34
+ PRIVACY_POLICY_CLICKED: string;
29
35
  LOGIN_MODAL_OPENED: string;
30
36
  LOGIN_MODAL_CLOSED: string;
31
37
  SOCIAL_LOGIN_SELECTED: string;
@@ -102,8 +102,12 @@ export interface IConnector<T> extends SafeEventEmitter {
102
102
  switchChain(params: {
103
103
  chainId: string;
104
104
  }): Promise<void>;
105
- getAuthTokenInfo(): Promise<AuthTokenInfo>;
106
- generateChallengeAndSign(authServerUrl?: string, accounts?: string[]): Promise<{
105
+ /**
106
+ * `chainId` is optional to keep the connector API backward compatible while still
107
+ * allowing multichain connectors to bind auth/signing to the caller's selected chain.
108
+ */
109
+ getAuthTokenInfo(chainId?: string): Promise<AuthTokenInfo>;
110
+ generateChallengeAndSign(authServerUrl?: string, accounts?: string[], chainId?: string): Promise<{
107
111
  challenge: string;
108
112
  signature: string;
109
113
  chainNamespace: ChainNamespaceType;
@@ -227,13 +227,14 @@ export type SDK_CONNECTED_EVENT_DATA = CONNECTED_EVENT_DATA & {
227
227
  loginMode: LoginModeType;
228
228
  pendingUserConsent?: boolean;
229
229
  };
230
- export type SDK_CONSENT_ACCEPTED_EVENT_DATA = {
230
+ export type SDK_CONSENT_ACCEPTED_EVENT_DATA = Partial<CONNECTED_EVENT_DATA> & {
231
231
  reconnected: boolean;
232
232
  };
233
+ export type SDK_CONSENT_REQUIRING_EVENT_DATA = Partial<CONNECTED_EVENT_DATA>;
233
234
  export type Web3AuthNoModalEvents = Omit<ConnectorEvents, "connected" | "errored" | "ready" | "consent_requiring" | "consent_accepted"> & {
234
235
  [CONNECTOR_EVENTS.READY]: () => void;
235
236
  [CONNECTOR_EVENTS.CONNECTED]: (data: SDK_CONNECTED_EVENT_DATA) => void;
236
- [CONNECTOR_EVENTS.CONSENT_REQUIRING]: () => void;
237
+ [CONNECTOR_EVENTS.CONSENT_REQUIRING]: (data: SDK_CONSENT_REQUIRING_EVENT_DATA) => void;
237
238
  [CONNECTOR_EVENTS.CONSENT_ACCEPTED]: (data: SDK_CONSENT_ACCEPTED_EVENT_DATA) => void;
238
239
  [CONNECTOR_EVENTS.ERRORED]: (error: Web3AuthError, loginMode: LoginModeType) => void;
239
240
  [CONNECTOR_EVENTS.CONNECTION_UPDATED]: (data: CONNECTION_UPDATED_EVENT_DATA) => void;
@@ -12,6 +12,7 @@ export declare enum DEFAULT_EIP155_METHODS {
12
12
  ADD_ETHEREUM_CHAIN = "wallet_addEthereumChain",
13
13
  SWITCH_ETHEREUM_CHAIN = "wallet_switchEthereumChain"
14
14
  }
15
+ export declare const NULL_ON_SUCCESS_METHODS: string[];
15
16
  export declare enum DEFAULT_SOLANA_METHODS {
16
17
  SIGN_TRANSACTION = "solana_signTransaction",
17
18
  SIGN_MESSAGE = "solana_signMessage"
@@ -95,7 +95,7 @@ export declare class Web3AuthNoModal extends SafeEventEmitter<Web3AuthNoModalEve
95
95
  */
96
96
  protected getInitialChainIdForConnector(connector: IConnector<unknown>): CustomChainConfig;
97
97
  protected completeConsentAcceptance(): Promise<void>;
98
- protected resolveLinkAccountChainId(chainId?: string | null): string;
98
+ protected resolveLinkAccountChainConfig(chainId?: string | null): CustomChainConfig;
99
99
  /**
100
100
  * Resolves the chain ID for a switch account operation.
101
101
  * If the account's chain namespace is the same as the current chain namespace, return the current chain ID.
@@ -106,6 +106,13 @@ const ANALYTICS_EVENTS = {
106
106
  MFA_ENABLEMENT_FAILED: "MFA Enablement Failed",
107
107
  MFA_MANAGEMENT_SELECTED: "MFA Management Selected",
108
108
  MFA_MANAGEMENT_FAILED: "MFA Management Failed",
109
+ // Consent Flow
110
+ USER_CONSENT_STARTED: "User Consent Started",
111
+ USER_CONSENT_ACCEPTED: "User Consent Accepted",
112
+ USER_CONSENT_DECLINED: "User Consent Declined",
113
+ USER_CONSENT_ERRORED: "User Consent Errored",
114
+ TERMS_OF_SERVICE_CLICKED: "Terms of Service Clicked",
115
+ PRIVACY_POLICY_CLICKED: "Privacy Policy Clicked",
109
116
  // Login Modal
110
117
  LOGIN_MODAL_OPENED: "Login Modal Opened",
111
118
  LOGIN_MODAL_CLOSED: "Login Modal Closed",
@@ -149,7 +149,7 @@ const getWalletServicesAnalyticsProperties = walletServicesConfig => {
149
149
  ws_default_portfolio: walletServicesConfig === null || walletServicesConfig === void 0 || (_walletServicesConfig10 = walletServicesConfig.whiteLabel) === null || _walletServicesConfig10 === void 0 ? void 0 : _walletServicesConfig10.defaultPortfolio
150
150
  };
151
151
  };
152
- const sdkVersion = "11.0.0";
152
+ const sdkVersion = "11.0.2";
153
153
  const getErrorAnalyticsProperties = error => {
154
154
  try {
155
155
  const code = error instanceof Web3AuthError ? error.code : error === null || error === void 0 ? void 0 : error.code;
@@ -490,7 +490,7 @@ class AuthConnector extends BaseConnector {
490
490
  accessToken,
491
491
  idToken
492
492
  } = await this.getPrimaryAuthSession(params.authSessionTokens);
493
- const walletProof = await this.createWalletLinkingProof(params.connectorToLink);
493
+ const walletProof = await this.createWalletLinkingProof(params.connectorToLink, chainId);
494
494
  const authServerUrl = citadelServerUrl(this.coreOptions.authBuildEnv);
495
495
  const result = await makeAccountLinkingRequest(authServerUrl, accessToken, {
496
496
  idToken,
@@ -683,7 +683,7 @@ class AuthConnector extends BaseConnector {
683
683
  }
684
684
  throw AccountLinkingError.requestFailed(`Unsupported chain namespace "${matchedAccount.chainNamespace}" for address "${address}".`);
685
685
  }
686
- async createWalletLinkingProof(connector) {
686
+ async createWalletLinkingProof(connector, chainId) {
687
687
  // Notify listeners that the linking wallet is about to be asked for a signature so the UI
688
688
  // (e.g. modal) can switch from a "connecting" loader to an "authorizing" prompt while the
689
689
  // user reviews the signature request inside their wallet. Emitted on the isolated wallet
@@ -691,11 +691,13 @@ class AuthConnector extends BaseConnector {
691
691
  connector.emit(CONNECTOR_EVENTS.AUTHORIZING, {
692
692
  connector: connector.name
693
693
  });
694
+ // Reuse the caller's target chain so multichain wallets generate the linking
695
+ // proof for the same namespace they were connected for.
694
696
  const {
695
697
  challenge,
696
698
  signature,
697
699
  chainNamespace
698
- } = await connector.generateChallengeAndSign();
700
+ } = await connector.generateChallengeAndSign(undefined, undefined, chainId);
699
701
  const address = await this.getLinkingWalletAddress(connector, chainNamespace);
700
702
  if (chainNamespace === CHAIN_NAMESPACES.EIP155) {
701
703
  return {
@@ -1,6 +1,7 @@
1
1
  import { signChallenge } from '@toruslabs/base-controllers';
2
2
  import { bytesToHexPrefixedString, utf8ToBytes } from '@toruslabs/metadata-helpers';
3
3
  import { EVM_METHOD_TYPES } from '@web3auth/ws-embed';
4
+ import { checksumAddress } from 'viem';
4
5
  import { generateSiweNonce } from 'viem/siwe';
5
6
  import { WalletLoginError, WalletInitializationError } from '../../base/errors/index.js';
6
7
  import { citadelServerUrl } from '../../base/utils.js';
@@ -54,9 +55,9 @@ class BaseEvmConnector extends BaseConnector {
54
55
  } = currentChainConfig;
55
56
  const authServer = authServerUrl || citadelServerUrl(this.coreOptions.authBuildEnv);
56
57
  const payload = {
57
- domain: window.location.origin,
58
+ domain: window.location.host,
58
59
  uri: window.location.href,
59
- address: accountsToUse[0],
60
+ address: checksumAddress(accountsToUse[0]),
60
61
  chainId: parseInt(chainId, 16),
61
62
  version: "1",
62
63
  nonce: generateSiweNonce(),
@@ -141,7 +141,12 @@ class MetaMaskConnector extends BaseConnector {
141
141
  this.disconnect();
142
142
  }
143
143
  },
144
- chainChanged: _chainId => {},
144
+ chainChanged: _chainId => {
145
+ // Keep Web3Auth state aligned with the wallet's actual EVM chain after connect/switch.
146
+ this.updateConnectorData({
147
+ chainId: _chainId
148
+ });
149
+ },
145
150
  connect: _result => {},
146
151
  disconnect: () => {
147
152
  if (this.connected) {
@@ -198,7 +203,7 @@ class MetaMaskConnector extends BaseConnector {
198
203
  ethereumProvider: this.evmProvider,
199
204
  solanaWallet: this.solanaProvider
200
205
  });
201
- if (options.getAuthTokenInfo) await this.getAuthTokenInfo();
206
+ if (options.getAuthTokenInfo) await this.getAuthTokenInfo(options.chainId);
202
207
  } else if (coreStatus === "connected" || coreStatus === "loaded" || coreStatus === "disconnected" || coreStatus === "pending") {
203
208
  this.status = CONNECTOR_STATUS.READY;
204
209
  this.emit(CONNECTOR_EVENTS.READY, WALLET_CONNECTORS.METAMASK);
@@ -266,13 +271,9 @@ class MetaMaskConnector extends BaseConnector {
266
271
  }
267
272
  }
268
273
 
269
- // // Switch EVM chain if not connected to the right one (Solana chains are handled by the wallet-standard provider)
270
- // if (chainConfig.chainNamespace === CHAIN_NAMESPACES.EIP155) {
271
- // const currentChainId = this.evmClient!.getChainId();
272
- // if (currentChainId !== chainId) {
273
- // await this.switchChain(chainConfig, true);
274
- // }
275
- // }
274
+ // sync the chain state after connect
275
+ // metamask might not be connected to the requested chain, so we need to sync the chain state to/from Web3Auth state after connect.
276
+ await this.syncChainStateAfterConnect(chainConfig);
276
277
 
277
278
  // check if connected
278
279
  if (this.multichainClient.status !== "connected") {
@@ -295,7 +296,7 @@ class MetaMaskConnector extends BaseConnector {
295
296
  solanaWallet: this.solanaProvider
296
297
  });
297
298
  if (getAuthTokenInfo) {
298
- await this.getAuthTokenInfo();
299
+ await this.getAuthTokenInfo(chainId);
299
300
  }
300
301
  return {
301
302
  ethereumProvider: this.evmProvider,
@@ -347,14 +348,11 @@ class MetaMaskConnector extends BaseConnector {
347
348
  connector: WALLET_CONNECTORS.METAMASK
348
349
  });
349
350
  }
350
- async getAuthTokenInfo() {
351
- var _this$evmProvider2, _this$coreOptions$cha;
351
+ async getAuthTokenInfo(chainId) {
352
352
  if (!this.canAuthorize) throw WalletLoginError.notConnectedError();
353
-
354
- // Determine the active chain: prefer Solana if no EVM provider, otherwise use EVM provider's chain
355
- const evmChainId = ((_this$evmProvider2 = this.evmProvider) === null || _this$evmProvider2 === void 0 ? void 0 : _this$evmProvider2.chainId) || ((_this$coreOptions$cha = this.coreOptions.chains.find(x => x.chainNamespace === CHAIN_NAMESPACES.EIP155)) === null || _this$coreOptions$cha === void 0 ? void 0 : _this$coreOptions$cha.chainId);
356
- const isSolanaOnly = !this.evmProvider && !!this.solanaProvider;
357
- const activeChainConfig = isSolanaOnly ? this.coreOptions.chains.find(x => x.chainNamespace === CHAIN_NAMESPACES.SOLANA) : this.evmProvider ? this.coreOptions.chains.find(x => x.chainId === evmChainId) : undefined;
353
+ // In multichain sessions both providers can exist at the same time, so auth must
354
+ // follow the caller-selected chain instead of inferring from provider availability.
355
+ const activeChainConfig = this.resolveAuthChainConfig(chainId);
358
356
  if (!activeChainConfig) throw WalletLoginError.connectionError("Chain config is not available");
359
357
  const {
360
358
  chainNamespace
@@ -374,7 +372,7 @@ class MetaMaskConnector extends BaseConnector {
374
372
  const {
375
373
  challenge,
376
374
  signature
377
- } = await this.generateChallengeAndSign(authServer, accounts);
375
+ } = await this.generateChallengeAndSign(authServer, accounts, activeChainConfig.chainId);
378
376
  return this.verifyAndAuthorize({
379
377
  chainNamespace,
380
378
  signedMessage: signature,
@@ -415,11 +413,8 @@ class MetaMaskConnector extends BaseConnector {
415
413
  chainConfiguration
416
414
  });
417
415
  }
418
- async generateChallengeAndSign(authServerUrl, accounts) {
419
- var _this$evmProvider3, _this$coreOptions$cha2;
420
- const evmChainId = ((_this$evmProvider3 = this.evmProvider) === null || _this$evmProvider3 === void 0 ? void 0 : _this$evmProvider3.chainId) || ((_this$coreOptions$cha2 = this.coreOptions.chains.find(x => x.chainNamespace === CHAIN_NAMESPACES.EIP155)) === null || _this$coreOptions$cha2 === void 0 ? void 0 : _this$coreOptions$cha2.chainId);
421
- const isSolanaOnly = !this.evmProvider && !!this.solanaProvider;
422
- const activeChainConfig = isSolanaOnly ? this.coreOptions.chains.find(x => x.chainNamespace === CHAIN_NAMESPACES.SOLANA) : this.evmProvider ? this.coreOptions.chains.find(x => x.chainId === evmChainId) : undefined;
416
+ async generateChallengeAndSign(authServerUrl, accounts, chainId) {
417
+ const activeChainConfig = this.resolveAuthChainConfig(chainId);
423
418
  if (!activeChainConfig) throw WalletLoginError.connectionError("Chain config is not available");
424
419
  const {
425
420
  chainNamespace
@@ -475,6 +470,48 @@ class MetaMaskConnector extends BaseConnector {
475
470
  }
476
471
  await this.initializationPromise;
477
472
  }
473
+ async syncChainStateAfterConnect(chainConfig) {
474
+ var _this$evmProvider2;
475
+ // EVM connectors can switch chains, so align the wallet with the requested chain
476
+ // before Web3Auth persists the active chain in controller state.
477
+ if (chainConfig.chainNamespace === CHAIN_NAMESPACES.EIP155 && ((_this$evmProvider2 = this.evmProvider) === null || _this$evmProvider2 === void 0 ? void 0 : _this$evmProvider2.chainId) !== chainConfig.chainId) {
478
+ await this.switchChain({
479
+ chainId: chainConfig.chainId
480
+ }, true);
481
+ } else if (chainConfig.chainNamespace === CHAIN_NAMESPACES.SOLANA) {
482
+ // For solana case, metamask connect the first available scope in priority order: mainnet > devnet > testnet.
483
+ // So, if the user requested chain is different from the connected chain,
484
+ // we need to update the connector data with the connected chain id to keep the Web3Auth state aligned.
485
+ if ("scope" in this.solanaProvider && typeof this.solanaProvider.scope === "string") {
486
+ var _this$coreOptions$cha;
487
+ const connectedSolChain = this.solanaProvider.scope;
488
+ const connectedChainConfig = (_this$coreOptions$cha = this.coreOptions.chains) === null || _this$coreOptions$cha === void 0 ? void 0 : _this$coreOptions$cha.find(chain => {
489
+ return getCaipChainId(chain) === connectedSolChain && chain.chainNamespace === CHAIN_NAMESPACES.SOLANA;
490
+ });
491
+ if (!connectedChainConfig) {
492
+ throw WalletLoginError.connectionError("Connected chain is not available in the chains config");
493
+ }
494
+ if (connectedChainConfig.chainId !== chainConfig.chainId) {
495
+ // since, switchChain is not supported for solana (in metamask connect),
496
+ // we will make use of the connector data to update the Web3Auth state.
497
+ this.updateConnectorData({
498
+ chainId: connectedChainConfig.chainId
499
+ });
500
+ }
501
+ }
502
+ }
503
+ }
504
+ resolveAuthChainConfig(chainId) {
505
+ var _this$evmProvider3, _this$coreOptions$cha2;
506
+ if (chainId) {
507
+ return this.coreOptions.chains.find(x => x.chainId === chainId);
508
+ }
509
+ const evmChainId = ((_this$evmProvider3 = this.evmProvider) === null || _this$evmProvider3 === void 0 ? void 0 : _this$evmProvider3.chainId) || ((_this$coreOptions$cha2 = this.coreOptions.chains.find(x => x.chainNamespace === CHAIN_NAMESPACES.EIP155)) === null || _this$coreOptions$cha2 === void 0 ? void 0 : _this$coreOptions$cha2.chainId);
510
+ const isSolanaOnly = !this.evmProvider && !!this.solanaProvider;
511
+
512
+ // Keep the old fallback for callers that do not pass a chainId yet.
513
+ return isSolanaOnly ? this.coreOptions.chains.find(x => x.chainNamespace === CHAIN_NAMESPACES.SOLANA) : this.evmProvider ? this.coreOptions.chains.find(x => x.chainId === evmChainId) : undefined;
514
+ }
478
515
  }
479
516
 
480
517
  /**
@@ -14,6 +14,9 @@ let DEFAULT_EIP155_METHODS = /*#__PURE__*/function (DEFAULT_EIP155_METHODS) {
14
14
  DEFAULT_EIP155_METHODS["SWITCH_ETHEREUM_CHAIN"] = "wallet_switchEthereumChain";
15
15
  return DEFAULT_EIP155_METHODS;
16
16
  }({});
17
+
18
+ // methods that return `null` on success
19
+ const NULL_ON_SUCCESS_METHODS = [DEFAULT_EIP155_METHODS.SWITCH_ETHEREUM_CHAIN, DEFAULT_EIP155_METHODS.ADD_ETHEREUM_CHAIN];
17
20
  let DEFAULT_SOLANA_METHODS = /*#__PURE__*/function (DEFAULT_SOLANA_METHODS) {
18
21
  DEFAULT_SOLANA_METHODS["SIGN_TRANSACTION"] = "solana_signTransaction";
19
22
  DEFAULT_SOLANA_METHODS["SIGN_MESSAGE"] = "solana_signMessage";
@@ -107,4 +110,4 @@ const getWalletConnectV2Settings = async (chains, projectID) => {
107
110
  };
108
111
  };
109
112
 
110
- export { DEFAULT_EIP155_METHODS, DEFAULT_EIP_155_EVENTS, DEFAULT_SOLANA_EVENTS, DEFAULT_SOLANA_METHODS, getNamespacesFromChains, getRequiredNamespaces, getSupportedEventsByNamespace, getSupportedMethodsByNamespace, getWalletConnectV2Settings };
113
+ export { DEFAULT_EIP155_METHODS, DEFAULT_EIP_155_EVENTS, DEFAULT_SOLANA_EVENTS, DEFAULT_SOLANA_METHODS, NULL_ON_SUCCESS_METHODS, getNamespacesFromChains, getRequiredNamespaces, getSupportedEventsByNamespace, getSupportedMethodsByNamespace, getWalletConnectV2Settings };
@@ -1,4 +1,4 @@
1
- export { DEFAULT_EIP155_METHODS, DEFAULT_EIP_155_EVENTS, DEFAULT_SOLANA_EVENTS, DEFAULT_SOLANA_METHODS, getNamespacesFromChains, getRequiredNamespaces, getSupportedEventsByNamespace, getSupportedMethodsByNamespace, getWalletConnectV2Settings } from './config.js';
1
+ export { DEFAULT_EIP155_METHODS, DEFAULT_EIP_155_EVENTS, DEFAULT_SOLANA_EVENTS, DEFAULT_SOLANA_METHODS, NULL_ON_SUCCESS_METHODS, getNamespacesFromChains, getRequiredNamespaces, getSupportedEventsByNamespace, getSupportedMethodsByNamespace, getWalletConnectV2Settings } from './config.js';
2
2
  import { walletConnectV2Connector } from './walletConnectV2Connector.js';
3
3
  export { WalletConnectV2Provider } from './WalletConnectV2Provider.js';
4
4
 
@@ -15,7 +15,7 @@ export { CONNECTOR_NAMES, EVM_CONNECTORS, MULTI_CHAIN_CONNECTORS, SOLANA_CONNECT
15
15
  export { CONNECTOR_NAMESPACES } from './base/chain/IChainInterface.js';
16
16
  export { CommonJRPCProvider } from './providers/base-provider/CommonJRPCProvider.js';
17
17
  export { CommonPrivateKeyProvider } from './providers/base-provider/commonPrivateKeyProvider.js';
18
- export { DEFAULT_EIP155_METHODS, DEFAULT_EIP_155_EVENTS, DEFAULT_SOLANA_EVENTS, DEFAULT_SOLANA_METHODS, getNamespacesFromChains, getRequiredNamespaces, getSupportedEventsByNamespace, getSupportedMethodsByNamespace, getWalletConnectV2Settings } from './connectors/wallet-connect-v2-connector/config.js';
18
+ export { DEFAULT_EIP155_METHODS, DEFAULT_EIP_155_EVENTS, DEFAULT_SOLANA_EVENTS, DEFAULT_SOLANA_METHODS, NULL_ON_SUCCESS_METHODS, getNamespacesFromChains, getRequiredNamespaces, getSupportedEventsByNamespace, getSupportedMethodsByNamespace, getWalletConnectV2Settings } from './connectors/wallet-connect-v2-connector/config.js';
19
19
  export { EIP1193_EVENTS } from './providers/base-provider/utils.js';
20
20
  export { EIP_7702_SUPPORTED_SMART_ACCOUNTS, LOGIN_MODE, MODAL_SIGN_IN_METHODS, SMART_ACCOUNT_WALLET_SCOPE, SOLANA_CAIP_CHAIN_MAP, WALLET_REGISTRY_URL, WEB3AUTH_STATE_STORAGE_KEY, WIDGET_TYPE } from './base/constants.js';
21
21
  export { EVM_PLUGINS, PLUGIN_EVENTS, PLUGIN_NAMESPACES, PLUGIN_STATUS, SOLANA_PLUGINS, WALLET_PLUGINS } from './base/plugin/IPlugin.js';
@@ -489,7 +489,9 @@ class Web3AuthNoModal extends SafeEventEmitter {
489
489
  };
490
490
  try {
491
491
  this.analytics.track(ANALYTICS_EVENTS.IDENTITY_TOKEN_STARTED, trackData);
492
- const authTokenInfo = await this.primaryConnector.getAuthTokenInfo();
492
+ // Thread the controller's active chain into connector auth so multichain
493
+ // connectors sign for the same chain the app/session is currently using.
494
+ const authTokenInfo = await this.primaryConnector.getAuthTokenInfo(this.currentChainId);
493
495
  this.analytics.track(ANALYTICS_EVENTS.IDENTITY_TOKEN_COMPLETED, trackData);
494
496
  return {
495
497
  idToken: authTokenInfo.idToken
@@ -526,7 +528,9 @@ class Web3AuthNoModal extends SafeEventEmitter {
526
528
  if (!(params !== null && params !== void 0 && params.connectorName)) {
527
529
  throw WalletInitializationError.invalidParams("connectorName is required when calling linkAccount on the no-modal SDK");
528
530
  }
529
- const chainId = this.resolveLinkAccountChainId(params.chainId);
531
+ const {
532
+ chainId
533
+ } = this.resolveLinkAccountChainConfig(params.chainId);
530
534
  const isolatedConnector = await this.createLinkingWalletConnector(params.connectorName, chainId);
531
535
  return this.linkAccountWithConnector(params.connectorName, chainId, isolatedConnector);
532
536
  }
@@ -928,12 +932,16 @@ class Web3AuthNoModal extends SafeEventEmitter {
928
932
  }));
929
933
  this.setActiveWalletConnectorKey();
930
934
  this.connectionReconnected = data.reconnected;
935
+ const {
936
+ activeAccount,
937
+ currentChainId
938
+ } = this.state;
931
939
 
932
940
  // when ssr is enabled, we need to get the idToken from the connector.
933
941
  if (this.coreOptions.ssr) {
934
942
  try {
935
943
  var _data$accessToken, _data$refreshToken;
936
- const data = await connector.getAuthTokenInfo();
944
+ const data = await connector.getAuthTokenInfo(currentChainId);
937
945
  if (!data.idToken) throw WalletLoginError.connectionError("No idToken found");
938
946
  await this.setState({
939
947
  idToken: data.idToken,
@@ -951,10 +959,6 @@ class Web3AuthNoModal extends SafeEventEmitter {
951
959
  }
952
960
  // The following block only hits during rehydration
953
961
 
954
- const {
955
- activeAccount,
956
- currentChainId
957
- } = this.state;
958
962
  let rehydrateWithLinkedAccount = false;
959
963
  // for rehydration, if the active account is not the primary account, i.e. not `null`, create an isolated connector and connect to the chain
960
964
  if (activeAccount && !activeAccount.isPrimary && activeAccount.connector !== WALLET_CONNECTORS.AUTH) {
@@ -1001,7 +1005,7 @@ class Web3AuthNoModal extends SafeEventEmitter {
1001
1005
  const pendingUserConsent = this.consentRequired && !this.state.hasUserConsent;
1002
1006
  if (pendingUserConsent && !isConnectAndSign) {
1003
1007
  this.status = CONNECTOR_STATUS.CONSENT_REQUIRING;
1004
- this.emit(CONNECTOR_EVENTS.CONSENT_REQUIRING);
1008
+ this.emit(CONNECTOR_EVENTS.CONSENT_REQUIRING, _objectSpread({}, data));
1005
1009
  log.debug("consent_requiring", this.status, this.primaryConnectorName);
1006
1010
  } else {
1007
1011
  // In CONNECT_AND_SIGN mode the AUTHORIZED handler can run before this point (e.g. when `ssr=true`
@@ -1124,7 +1128,13 @@ class Web3AuthNoModal extends SafeEventEmitter {
1124
1128
  await this.clearCache();
1125
1129
  this.emit(CONNECTOR_EVENTS.REHYDRATION_ERROR, error);
1126
1130
  });
1127
- connector.on(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, data => {
1131
+ connector.on(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, async data => {
1132
+ if (this.shouldIgnoreInactiveConnectorEvent(connector, CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED)) return;
1133
+ // External wallets can resolve to a different active chain than the requested one,
1134
+ // so let connector-reported chain updates reconcile Web3Auth state after connect.
1135
+ 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") {
1136
+ await this.setCurrentChain(data.data.chainId);
1137
+ }
1128
1138
  log.debug("connector data updated", data);
1129
1139
  this.emit(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, data);
1130
1140
  });
@@ -1162,7 +1172,9 @@ class Web3AuthNoModal extends SafeEventEmitter {
1162
1172
  // if the user has not consented yet, we will ask for consent
1163
1173
  if (this.consentRequired && this.connection && !this.state.hasUserConsent) {
1164
1174
  this.status = CONNECTOR_STATUS.CONSENT_REQUIRING;
1165
- this.emit(CONNECTOR_EVENTS.CONSENT_REQUIRING);
1175
+ this.emit(CONNECTOR_EVENTS.CONSENT_REQUIRING, {
1176
+ connectorName: data.connector
1177
+ });
1166
1178
  log.debug("consent_requiring", this.status, this.primaryConnectorName);
1167
1179
  } else {
1168
1180
  this.status = CONNECTOR_STATUS.AUTHORIZED;
@@ -1226,12 +1238,14 @@ class Web3AuthNoModal extends SafeEventEmitter {
1226
1238
  reconnected: this.connectionReconnected
1227
1239
  });
1228
1240
  }
1229
- resolveLinkAccountChainId(chainId) {
1241
+ resolveLinkAccountChainConfig(chainId) {
1242
+ var _this$coreOptions$cha7;
1230
1243
  const finalChainId = chainId || this.state.currentChainId;
1231
- if (!finalChainId) {
1244
+ const chainConfig = (_this$coreOptions$cha7 = this.coreOptions.chains) === null || _this$coreOptions$cha7 === void 0 ? void 0 : _this$coreOptions$cha7.find(chain => chain.chainId === finalChainId);
1245
+ if (!chainConfig) {
1232
1246
  throw AccountLinkingError.walletProofFailed("No chainId is available. Please specify chainId in LinkAccountParams or ensure the SDK has an active chain.");
1233
1247
  }
1234
- return finalChainId;
1248
+ return chainConfig;
1235
1249
  }
1236
1250
 
1237
1251
  /**
@@ -145,13 +145,23 @@ class AccountAbstractionProvider extends BaseProvider {
145
145
  });
146
146
  const provider = providerFromEngineV2(engine);
147
147
  this.updateProviderEngineProxy(provider);
148
- eoaProvider.once("chainChanged", chainId => {
148
+ const chainChangedHandler = chainId => {
149
149
  this.update({
150
150
  chainId
151
151
  });
152
152
  this.setupChainSwitchMiddleware();
153
153
  this.emit("chainChanged", chainId);
154
- });
154
+ if (eoaProvider !== null && eoaProvider !== void 0 && eoaProvider.removeListener && typeof eoaProvider.removeListener === "function") {
155
+ eoaProvider.removeListener("chainChanged", chainChangedHandler);
156
+ }
157
+ };
158
+ if (eoaProvider !== null && eoaProvider !== void 0 && eoaProvider.once && typeof eoaProvider.once === "function") {
159
+ eoaProvider.once("chainChanged", chainChangedHandler);
160
+ } else {
161
+ // some providers like trust wallet does not have `once` method, so we use `on` instead
162
+ // and cleanup the listener after the event triggers once
163
+ eoaProvider.on("chainChanged", chainChangedHandler);
164
+ }
155
165
  }
156
166
  async updateAccount(_params) {
157
167
  throw providerErrors.unsupportedMethod("updateAccount. Please call it on eoaProvider");
@@ -1,6 +1,7 @@
1
1
  import _objectSpread from '@babel/runtime/helpers/objectSpread2';
2
2
  import { METHOD_TYPES, EIP_5792_METHODS, EIP_7702_METHODS } from '@toruslabs/ethereum-controllers';
3
3
  import { createScaffoldMiddlewareV2, providerErrors, rpcErrors } from '@web3auth/auth';
4
+ import { NULL_ON_SUCCESS_METHODS } from '../../../connectors/wallet-connect-v2-connector/config.js';
4
5
 
5
6
  async function createAaMiddleware({
6
7
  eoaProvider,
@@ -199,10 +200,17 @@ function providerAsMiddleware(provider) {
199
200
  return async ({
200
201
  request
201
202
  }) => {
202
- return provider.request({
203
+ const result = await provider.request({
203
204
  method: request.method,
204
205
  params: request.params
205
206
  });
207
+ if (result === undefined && NULL_ON_SUCCESS_METHODS.includes(request.method)) {
208
+ // For some RPC requests, such as `wallet_switchEthereumChain`, the standard rpc result is `null`.
209
+ // However, some wallet providers might return `undefined` instead and causing the JRPCEngineV2 to throw `Nothing ended the request` error.
210
+ // So, we handle this case by returning `null` instead, so that JRPCEngineV2 won't throw `Nothing ended the request` error
211
+ return null;
212
+ }
213
+ return result;
206
214
  };
207
215
  }
208
216
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@web3auth/no-modal",
3
- "version": "11.0.0",
3
+ "version": "11.0.2",
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": "84b5f0c887209f24f098b7eea634747193bc1f2c"
255
+ "gitHead": "de91630f1420601b3a9b2377c0dff760b8674013"
256
256
  }