thirdweb 5.105.7-nightly-4c6a421d64336d7c18956a4128fea40866b9c9b1-20250706232018 → 5.105.7

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 (66) hide show
  1. package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js +2 -2
  2. package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
  3. package/dist/cjs/react/web/ui/Bridge/BuyWidget.js +0 -1
  4. package/dist/cjs/react/web/ui/Bridge/BuyWidget.js.map +1 -1
  5. package/dist/cjs/react/web/ui/Bridge/CheckoutWidget.js +0 -1
  6. package/dist/cjs/react/web/ui/Bridge/CheckoutWidget.js.map +1 -1
  7. package/dist/cjs/react/web/ui/Bridge/QuoteLoader.js +5 -1
  8. package/dist/cjs/react/web/ui/Bridge/QuoteLoader.js.map +1 -1
  9. package/dist/cjs/react/web/ui/Bridge/TransactionWidget.js +0 -1
  10. package/dist/cjs/react/web/ui/Bridge/TransactionWidget.js.map +1 -1
  11. package/dist/cjs/react/web/ui/PayEmbed.js +1 -1
  12. package/dist/cjs/react/web/ui/PayEmbed.js.map +1 -1
  13. package/dist/cjs/version.js +1 -1
  14. package/dist/cjs/version.js.map +1 -1
  15. package/dist/cjs/wallets/create-wallet.js +1 -9
  16. package/dist/cjs/wallets/create-wallet.js.map +1 -1
  17. package/dist/cjs/wallets/native/create-wallet.js +1 -9
  18. package/dist/cjs/wallets/native/create-wallet.js.map +1 -1
  19. package/dist/cjs/wallets/wallet-connect/controller.js +103 -62
  20. package/dist/cjs/wallets/wallet-connect/controller.js.map +1 -1
  21. package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js +2 -2
  22. package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
  23. package/dist/esm/react/web/ui/Bridge/BuyWidget.js +0 -1
  24. package/dist/esm/react/web/ui/Bridge/BuyWidget.js.map +1 -1
  25. package/dist/esm/react/web/ui/Bridge/CheckoutWidget.js +0 -1
  26. package/dist/esm/react/web/ui/Bridge/CheckoutWidget.js.map +1 -1
  27. package/dist/esm/react/web/ui/Bridge/QuoteLoader.js +5 -1
  28. package/dist/esm/react/web/ui/Bridge/QuoteLoader.js.map +1 -1
  29. package/dist/esm/react/web/ui/Bridge/TransactionWidget.js +0 -1
  30. package/dist/esm/react/web/ui/Bridge/TransactionWidget.js.map +1 -1
  31. package/dist/esm/react/web/ui/PayEmbed.js +1 -1
  32. package/dist/esm/react/web/ui/PayEmbed.js.map +1 -1
  33. package/dist/esm/version.js +1 -1
  34. package/dist/esm/version.js.map +1 -1
  35. package/dist/esm/wallets/create-wallet.js +1 -9
  36. package/dist/esm/wallets/create-wallet.js.map +1 -1
  37. package/dist/esm/wallets/native/create-wallet.js +1 -9
  38. package/dist/esm/wallets/native/create-wallet.js.map +1 -1
  39. package/dist/esm/wallets/wallet-connect/controller.js +104 -63
  40. package/dist/esm/wallets/wallet-connect/controller.js.map +1 -1
  41. package/dist/types/react/web/ui/Bridge/BuyWidget.d.ts.map +1 -1
  42. package/dist/types/react/web/ui/Bridge/CheckoutWidget.d.ts.map +1 -1
  43. package/dist/types/react/web/ui/Bridge/QuoteLoader.d.ts +4 -4
  44. package/dist/types/react/web/ui/Bridge/QuoteLoader.d.ts.map +1 -1
  45. package/dist/types/react/web/ui/Bridge/TransactionWidget.d.ts.map +1 -1
  46. package/dist/types/react/web/ui/PayEmbed.d.ts.map +1 -1
  47. package/dist/types/version.d.ts +1 -1
  48. package/dist/types/version.d.ts.map +1 -1
  49. package/dist/types/wallets/create-wallet.d.ts.map +1 -1
  50. package/dist/types/wallets/native/create-wallet.d.ts.map +1 -1
  51. package/dist/types/wallets/wallet-connect/controller.d.ts +2 -2
  52. package/dist/types/wallets/wallet-connect/controller.d.ts.map +1 -1
  53. package/dist/types/wallets/wallet-connect/types.d.ts +3 -12
  54. package/dist/types/wallets/wallet-connect/types.d.ts.map +1 -1
  55. package/package.json +2 -2
  56. package/src/react/web/ui/Bridge/BridgeOrchestrator.tsx +1 -1
  57. package/src/react/web/ui/Bridge/BuyWidget.tsx +0 -1
  58. package/src/react/web/ui/Bridge/CheckoutWidget.tsx +0 -1
  59. package/src/react/web/ui/Bridge/QuoteLoader.tsx +9 -5
  60. package/src/react/web/ui/Bridge/TransactionWidget.tsx +0 -1
  61. package/src/react/web/ui/PayEmbed.tsx +3 -0
  62. package/src/version.ts +1 -1
  63. package/src/wallets/create-wallet.ts +1 -8
  64. package/src/wallets/native/create-wallet.ts +1 -8
  65. package/src/wallets/wallet-connect/controller.ts +164 -101
  66. package/src/wallets/wallet-connect/types.ts +16 -12
@@ -1,19 +1,10 @@
1
+ import type { EthereumProvider } from "@walletconnect/ethereum-provider";
1
2
  import type { Chain } from "../../chains/types.js";
2
3
  import type { ThirdwebClient } from "../../client/client.js";
3
4
  import type { Prettify } from "../../utils/type-utils.js";
4
5
  import type { AppMetadata } from "../types.js";
5
- type WalletConnectQRCodeModalOptions = {
6
- themeMode?: "light" | "dark";
7
- themeVariables?: Record<string, string>;
8
- desktopWallets?: Record<string, unknown>[];
9
- enableExplorer?: boolean;
10
- explorerRecommendedWalletIds?: string[];
11
- explorerExcludedWalletIds?: string[];
12
- mobileWallets?: Record<string, unknown>[];
13
- privacyPolicyUrl?: string;
14
- termsOfServiceUrl?: string;
15
- walletImages?: Record<string, string>;
16
- };
6
+ type EthereumProviderOptions = Parameters<(typeof EthereumProvider)["init"]>[0];
7
+ type WalletConnectQRCodeModalOptions = Pick<NonNullable<EthereumProviderOptions["qrModalOptions"]>, "themeMode" | "themeVariables" | "desktopWallets" | "enableExplorer" | "explorerRecommendedWalletIds" | "explorerExcludedWalletIds" | "mobileWallets" | "privacyPolicyUrl" | "termsOfServiceUrl" | "walletImages">;
17
8
  export type WalletConnectConfig = {
18
9
  /**
19
10
  * Your project’s unique identifier that can be obtained at https://cloud.walletconnect.com/
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/wallets/wallet-connect/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,KAAK,+BAA+B,GAAG;IACrC,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAC3C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC;IACxC,yBAAyB,CAAC,EAAE,MAAM,EAAE,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAC1C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd;;;;;;;;;;;;;;OAcG;IACH,MAAM,EAAE,cAAc,CAAC;IAEvB,aAAa,CAAC,EAAE,QAAQ,CACtB,mBAAmB,GAAG;QACpB;;;;;;;;;;;;;;;;;;;;;;;;;WAyBG;QACH,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC;QACzB;;;;;;;;;;;;;;;;;WAiBG;QACH,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB;;WAEG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB;;;WAGG;QACH,cAAc,CAAC,EAAE,+BAA+B,CAAC;QACjD;;;;;;;;;;;;;WAaG;QACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;KACvC,CACF,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;;;;;;;;;;;OAcG;IACH,MAAM,EAAE,cAAc,CAAC;IAEvB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/wallets/wallet-connect/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,KAAK,uBAAuB,GAAG,UAAU,CAAC,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhF,KAAK,+BAA+B,GAAG,IAAI,CACzC,WAAW,CAAC,uBAAuB,CAAC,gBAAgB,CAAC,CAAC,EACpD,WAAW,GACX,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,8BAA8B,GAC9B,2BAA2B,GAC3B,eAAe,GACf,kBAAkB,GAClB,mBAAmB,GACnB,cAAc,CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd;;;;;;;;;;;;;;OAcG;IACH,MAAM,EAAE,cAAc,CAAC;IAEvB,aAAa,CAAC,EAAE,QAAQ,CACtB,mBAAmB,GAAG;QACpB;;;;;;;;;;;;;;;;;;;;;;;;;WAyBG;QACH,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC;QACzB;;;;;;;;;;;;;;;;;WAiBG;QACH,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB;;WAEG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB;;;WAGG;QACH,cAAc,CAAC,EAAE,+BAA+B,CAAC;QACjD;;;;;;;;;;;;;WAaG;QACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;KACvC,CACF,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;;;;;;;;;;;OAcG;IACH,MAAM,EAAE,cAAc,CAAC;IAEvB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC"}
package/package.json CHANGED
@@ -23,8 +23,8 @@
23
23
  "@radix-ui/react-tooltip": "1.2.7",
24
24
  "@storybook/react": "9.0.15",
25
25
  "@tanstack/react-query": "5.81.5",
26
+ "@walletconnect/ethereum-provider": "2.20.1",
26
27
  "@walletconnect/sign-client": "2.20.1",
27
- "@walletconnect/universal-provider": "2.21.4",
28
28
  "abitype": "1.0.8",
29
29
  "cross-spawn": "7.0.6",
30
30
  "fuse.js": "7.1.0",
@@ -375,7 +375,7 @@
375
375
  }
376
376
  },
377
377
  "typings": "./dist/types/exports/thirdweb.d.ts",
378
- "version": "5.105.7-nightly-4c6a421d64336d7c18956a4128fea40866b9c9b1-20250706232018",
378
+ "version": "5.105.7",
379
379
  "scripts": {
380
380
  "bench": "vitest -c ./test/vitest.config.ts bench",
381
381
  "bench:compare": "bun run ./benchmarks/run.ts",
@@ -292,7 +292,6 @@ export function BridgeOrchestrator({
292
292
  amount={state.context.destinationAmount}
293
293
  client={client}
294
294
  destinationToken={state.context.destinationToken}
295
- mode={uiOptions.mode}
296
295
  onBack={() => {
297
296
  send({ type: "BACK" });
298
297
  }}
@@ -302,6 +301,7 @@ export function BridgeOrchestrator({
302
301
  paymentMethod={state.context.selectedPaymentMethod}
303
302
  purchaseData={purchaseData}
304
303
  receiver={state.context.receiverAddress}
304
+ uiOptions={uiOptions}
305
305
  />
306
306
  )}
307
307
 
@@ -282,7 +282,6 @@ export function BuyWidget(props: BuyWidgetProps) {
282
282
  toChainId: props.chain.id,
283
283
  toToken: props.tokenAddress,
284
284
  });
285
- return true;
286
285
  },
287
286
  queryKey: ["buy_widget:render"],
288
287
  });
@@ -265,7 +265,6 @@ export function CheckoutWidget(props: CheckoutWidgetProps) {
265
265
  toChainId: props.chain.id,
266
266
  toToken: props.tokenAddress,
267
267
  });
268
- return true;
269
268
  },
270
269
  queryKey: ["checkout_widget:render"],
271
270
  });
@@ -17,6 +17,7 @@ import { Container } from "../components/basic.js";
17
17
  import { Spacer } from "../components/Spacer.js";
18
18
  import { Spinner } from "../components/Spinner.js";
19
19
  import { Text } from "../components/text.js";
20
+ import type { UIOptions } from "./BridgeOrchestrator.js";
20
21
 
21
22
  interface QuoteLoaderProps {
22
23
  /**
@@ -78,14 +79,13 @@ interface QuoteLoaderProps {
78
79
  paymentLinkId?: string;
79
80
 
80
81
  /**
81
- * Fee payer for direct transfers (defaults to sender)
82
+ * UI options
82
83
  */
83
- feePayer?: "sender" | "receiver";
84
- mode: "fund_wallet" | "direct_payment" | "transaction";
84
+ uiOptions: UIOptions;
85
85
  }
86
86
 
87
87
  export function QuoteLoader({
88
- mode,
88
+ uiOptions,
89
89
  destinationToken,
90
90
  paymentMethod,
91
91
  amount,
@@ -96,10 +96,14 @@ export function QuoteLoader({
96
96
  onError,
97
97
  purchaseData,
98
98
  paymentLinkId,
99
- feePayer,
100
99
  }: QuoteLoaderProps) {
101
100
  // For now, we'll use a simple buy operation
102
101
  // This will be expanded to handle different bridge types based on the payment method
102
+ const feePayer =
103
+ uiOptions.mode === "direct_payment"
104
+ ? uiOptions.paymentInfo.feePayer
105
+ : undefined;
106
+ const mode = uiOptions.mode;
103
107
  const request: BridgePrepareRequest = getBridgeParams({
104
108
  amount,
105
109
  client,
@@ -292,7 +292,6 @@ export function TransactionWidget(props: TransactionWidgetProps) {
292
292
  event: "ub:ui:transaction_widget:render",
293
293
  toToken: props.tokenAddress,
294
294
  });
295
- return true;
296
295
  },
297
296
  queryKey: ["transaction_widget:render"],
298
297
  });
@@ -380,6 +380,9 @@ export function PayEmbed(props: PayEmbedProps) {
380
380
  chain={props.payOptions.paymentInfo.chain}
381
381
  client={props.client}
382
382
  description={metadata?.description}
383
+ feePayer={
384
+ props.payOptions.paymentInfo.feePayer === "sender" ? "user" : "seller"
385
+ }
383
386
  image={metadata?.image}
384
387
  name={metadata?.name || "Checkout"}
385
388
  onSuccess={() => props.payOptions?.onPurchaseSuccess?.()}
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "5.105.7-nightly-4c6a421d64336d7c18956a4128fea40866b9c9b1-20250706232018";
1
+ export const version = "5.105.7";
@@ -399,14 +399,7 @@ export function createWallet<const ID extends WalletId>(
399
399
  getConfig: () => args[1],
400
400
  id,
401
401
  subscribe: emitter.subscribe,
402
- switchChain: async (c) => {
403
- try {
404
- await handleSwitchChain(c);
405
- chain = c;
406
- } catch (e) {
407
- console.error("Error switching chain", e);
408
- }
409
- },
402
+ switchChain: (c) => handleSwitchChain(c),
410
403
  };
411
404
  return wallet;
412
405
  }
@@ -230,14 +230,7 @@ export function createWallet<const ID extends WalletId>(
230
230
  getConfig: () => args[1],
231
231
  id,
232
232
  subscribe: emitter.subscribe,
233
- switchChain: async (c) => {
234
- try {
235
- await handleSwitchChain(c);
236
- chain = c;
237
- } catch (e) {
238
- console.error("Error switching chain", e);
239
- }
240
- },
233
+ switchChain: (c) => handleSwitchChain(c),
241
234
  };
242
235
  return wallet;
243
236
  }
@@ -1,4 +1,4 @@
1
- import type { UniversalProvider } from "@walletconnect/universal-provider";
1
+ import type { EthereumProvider } from "@walletconnect/ethereum-provider";
2
2
  import type { Address } from "abitype";
3
3
  import {
4
4
  getTypesForEIP712Domain,
@@ -11,7 +11,11 @@ import {
11
11
  } from "viem";
12
12
  import { trackTransaction } from "../../analytics/track/transaction.js";
13
13
  import type { Chain } from "../../chains/types.js";
14
- import { getCachedChain, getRpcUrlForChain } from "../../chains/utils.js";
14
+ import {
15
+ getCachedChain,
16
+ getChainMetadata,
17
+ getRpcUrlForChain,
18
+ } from "../../chains/utils.js";
15
19
  import type { ThirdwebClient } from "../../client/client.js";
16
20
  import { getAddress } from "../../utils/address.js";
17
21
  import {
@@ -36,6 +40,7 @@ import type {
36
40
  Wallet,
37
41
  } from "../interfaces/wallet.js";
38
42
  import type { DisconnectFn, SwitchChainFn } from "../types.js";
43
+ import { getValidPublicRPCUrl } from "../utils/chains.js";
39
44
  import { getDefaultAppMetadata } from "../utils/defaultDappMetadata.js";
40
45
  import { normalizeChainId } from "../utils/normalizeChainId.js";
41
46
  import type { WalletEmitter } from "../wallet-emitter.js";
@@ -43,9 +48,7 @@ import type { WalletId } from "../wallet-types.js";
43
48
  import { DEFAULT_PROJECT_ID, NAMESPACE } from "./constants.js";
44
49
  import type { WCAutoConnectOptions, WCConnectOptions } from "./types.js";
45
50
 
46
- type WCProvider = InstanceType<typeof UniversalProvider>;
47
-
48
- let cachedProvider: WCProvider | null = null;
51
+ type WCProvider = InstanceType<typeof EthereumProvider>;
49
52
 
50
53
  type SavedConnectParams = {
51
54
  optionalChains?: Chain[];
@@ -53,6 +56,10 @@ type SavedConnectParams = {
53
56
  pairingTopic?: string;
54
57
  };
55
58
 
59
+ const ADD_ETH_CHAIN_METHOD = "wallet_addEthereumChain";
60
+
61
+ const defaultShowQrModal = true;
62
+
56
63
  const storageKeys = {
57
64
  lastUsedChainId: "tw.wc.lastUsedChainId",
58
65
  requestedChains: "tw.wc.requestedChains",
@@ -116,56 +123,37 @@ export async function connectWC(
116
123
  }
117
124
  }
118
125
 
119
- // For UniversalProvider, we still need chain configuration for session management
120
- const { chains: chainsToRequest, rpcMap } = getChainsToRequest({
126
+ const {
127
+ rpcMap,
128
+ requiredChain,
129
+ optionalChains: chainsToRequest,
130
+ } = getChainsToRequest({
121
131
  chain: chainToRequest,
122
132
  client: options.client,
123
133
  optionalChains: optionalChains,
124
134
  });
125
135
 
126
- if (!provider.session) {
127
- // For UniversalProvider, we need to connect with namespaces
136
+ if (provider.session) {
128
137
  await provider.connect({
129
138
  ...(wcOptions?.pairingTopic
130
139
  ? { pairingTopic: wcOptions?.pairingTopic }
131
140
  : {}),
132
- namespaces: {
133
- [NAMESPACE]: {
134
- chains: chainsToRequest,
135
- events: ["chainChanged", "accountsChanged"],
136
- methods: [
137
- "eth_sendTransaction",
138
- "eth_signTransaction",
139
- "eth_sign",
140
- "personal_sign",
141
- "eth_signTypedData",
142
- "wallet_switchEthereumChain",
143
- "wallet_addEthereumChain",
144
- ],
145
- rpcMap,
146
- },
147
- },
141
+ chains: requiredChain ? [requiredChain.id] : undefined,
142
+ optionalChains: chainsToRequest,
143
+ rpcMap: rpcMap,
148
144
  });
149
145
  }
150
146
 
151
- setRequestedChainsIds(
152
- chainsToRequest.map((x) => Number(x.split(":")[1])),
153
- storage,
154
- );
155
- const currentChainId = chainsToRequest[0]?.split(":")[1] || 1;
156
- const providerChainId = normalizeChainId(currentChainId);
157
- const accounts: string[] = await provider.request(
158
- {
159
- method: "eth_requestAccounts",
160
- params: [],
161
- },
162
- `eip155:${providerChainId}`,
163
- );
164
- const address = accounts[0];
147
+ setRequestedChainsIds(chainsToRequest, storage);
148
+ // If session exists and chains are authorized, enable provider for required chain
149
+ const addresses = await provider.enable();
150
+ const address = addresses[0];
165
151
  if (!address) {
166
152
  throw new Error("No accounts found on provider.");
167
153
  }
168
154
 
155
+ const providerChainId = normalizeChainId(provider.chainId);
156
+
169
157
  const chain =
170
158
  options.chain && options.chain.id === providerChainId
171
159
  ? options.chain
@@ -221,19 +209,16 @@ export async function autoConnectWC(
221
209
  },
222
210
  walletId,
223
211
  sessionHandler,
212
+ true, // is auto connect
224
213
  );
225
214
 
226
- // For UniversalProvider, get accounts from enable() method
227
- const addresses = await provider.enable();
228
- const address = addresses[0];
215
+ const address = provider.accounts[0];
229
216
 
230
217
  if (!address) {
231
218
  throw new Error("No accounts found on provider.");
232
219
  }
233
220
 
234
- // For UniversalProvider, get chainId from the session namespaces or use default
235
- const currentChainId = options.chain?.id || 1;
236
- const providerChainId = normalizeChainId(currentChainId);
221
+ const providerChainId = normalizeChainId(provider.chainId);
237
222
 
238
223
  const chain =
239
224
  options.chain && options.chain.id === providerChainId
@@ -249,15 +234,12 @@ async function initProvider(
249
234
  options: WCConnectOptions,
250
235
  walletId: WCSupportedWalletIds | "walletConnect",
251
236
  sessionRequestHandler?: (uri: string) => void | Promise<void>,
237
+ isAutoConnect = false,
252
238
  ) {
253
- if (cachedProvider) {
254
- return cachedProvider;
255
- }
256
-
257
239
  const walletInfo = await getWalletInfo(walletId);
258
240
  const wcOptions = options.walletConnect;
259
- const { UniversalProvider } = await import(
260
- "@walletconnect/universal-provider"
241
+ const { EthereumProvider, OPTIONAL_EVENTS, OPTIONAL_METHODS } = await import(
242
+ "@walletconnect/ethereum-provider"
261
243
  );
262
244
 
263
245
  let optionalChains: Chain[] | undefined = wcOptions?.optionalChains;
@@ -271,7 +253,19 @@ async function initProvider(
271
253
  }
272
254
  }
273
255
 
274
- const provider = await UniversalProvider.init({
256
+ const {
257
+ rpcMap,
258
+ requiredChain,
259
+ optionalChains: chainsToRequest,
260
+ } = getChainsToRequest({
261
+ chain: chainToRequest,
262
+ client: options.client,
263
+ optionalChains: optionalChains,
264
+ });
265
+
266
+ const provider = await EthereumProvider.init({
267
+ chains: requiredChain ? [requiredChain.id] : undefined,
268
+ disableProviderPing: true,
275
269
  metadata: {
276
270
  description:
277
271
  wcOptions?.appMetadata?.description ||
@@ -282,11 +276,31 @@ async function initProvider(
282
276
  name: wcOptions?.appMetadata?.name || getDefaultAppMetadata().name,
283
277
  url: wcOptions?.appMetadata?.url || getDefaultAppMetadata().url,
284
278
  },
279
+ optionalChains: chainsToRequest,
280
+ optionalEvents: OPTIONAL_EVENTS,
281
+ optionalMethods: OPTIONAL_METHODS,
285
282
  projectId: wcOptions?.projectId || DEFAULT_PROJECT_ID,
283
+ qrModalOptions: wcOptions?.qrModalOptions,
284
+ rpcMap: rpcMap,
285
+ showQrModal:
286
+ wcOptions?.showQrModal === undefined
287
+ ? sessionRequestHandler
288
+ ? false
289
+ : defaultShowQrModal
290
+ : wcOptions.showQrModal,
286
291
  });
287
292
 
288
293
  provider.events.setMaxListeners(Number.POSITIVE_INFINITY);
289
294
 
295
+ // disconnect the provider if chains are stale when (if not auto connecting)
296
+ if (!isAutoConnect) {
297
+ // const isStale = await isChainsStale(provider, chainsToRequest);
298
+
299
+ if (provider.session) {
300
+ await provider.disconnect();
301
+ }
302
+ }
303
+
290
304
  if (walletId !== "walletConnect") {
291
305
  async function handleSessionRequest() {
292
306
  const walletLinkToOpen =
@@ -300,16 +314,12 @@ async function initProvider(
300
314
  }
301
315
  }
302
316
 
303
- // For UniversalProvider, use different event handling
304
- provider.on("session_request_sent", handleSessionRequest);
317
+ provider.signer.client.on("session_request_sent", handleSessionRequest);
305
318
  provider.events.addListener("disconnect", () => {
306
- provider.off("session_request_sent", handleSessionRequest);
307
- cachedProvider = null;
319
+ provider.signer.client.off("session_request_sent", handleSessionRequest);
308
320
  });
309
321
  }
310
322
 
311
- cachedProvider = provider;
312
-
313
323
  return provider;
314
324
  }
315
325
 
@@ -317,31 +327,26 @@ function createAccount({
317
327
  provider,
318
328
  address,
319
329
  client,
320
- chain,
321
330
  }: {
322
331
  provider: WCProvider;
323
332
  address: string;
324
333
  client: ThirdwebClient;
325
- chain: Chain;
326
334
  }) {
327
335
  const account: Account = {
328
336
  address: getAddress(address),
329
337
  async sendTransaction(tx: SendTransactionOption) {
330
- const transactionHash = (await provider.request(
331
- {
332
- method: "eth_sendTransaction",
333
- params: [
334
- {
335
- data: tx.data,
336
- from: getAddress(address),
337
- gas: tx.gas ? numberToHex(tx.gas) : undefined,
338
- to: tx.to as Address,
339
- value: tx.value ? numberToHex(tx.value) : undefined,
340
- },
341
- ],
342
- },
343
- `eip155:${tx.chainId}`,
344
- )) as Hex;
338
+ const transactionHash = (await provider.request({
339
+ method: "eth_sendTransaction",
340
+ params: [
341
+ {
342
+ data: tx.data,
343
+ from: getAddress(address),
344
+ gas: tx.gas ? numberToHex(tx.gas) : undefined,
345
+ to: tx.to as Address,
346
+ value: tx.value ? numberToHex(tx.value) : undefined,
347
+ },
348
+ ],
349
+ })) as Hex;
345
350
 
346
351
  trackTransaction({
347
352
  chainId: tx.chainId,
@@ -367,13 +372,10 @@ function createAccount({
367
372
  }
368
373
  return message.raw;
369
374
  })();
370
- return provider.request(
371
- {
372
- method: "personal_sign",
373
- params: [messageToSign, this.address],
374
- },
375
- `eip155:${chain.id}`,
376
- );
375
+ return provider.request({
376
+ method: "personal_sign",
377
+ params: [messageToSign, this.address],
378
+ });
377
379
  },
378
380
  async signTypedData(_data) {
379
381
  const data = parseTypedData(_data);
@@ -396,13 +398,10 @@ function createAccount({
396
398
  types,
397
399
  });
398
400
 
399
- return await provider.request(
400
- {
401
- method: "eth_signTypedData_v4",
402
- params: [this.address, typedData],
403
- },
404
- `eip155:${chain.id}`,
405
- );
401
+ return await provider.request({
402
+ method: "eth_signTypedData_v4",
403
+ params: [this.address, typedData],
404
+ });
406
405
  },
407
406
  };
408
407
 
@@ -417,14 +416,13 @@ function onConnect(
417
416
  storage: AsyncStorage,
418
417
  client: ThirdwebClient,
419
418
  ): [Account, Chain, DisconnectFn, SwitchChainFn] {
420
- const account = createAccount({ address, chain, client, provider });
419
+ const account = createAccount({ address, client, provider });
421
420
 
422
421
  async function disconnect() {
423
422
  provider.removeListener("accountsChanged", onAccountsChanged);
424
423
  provider.removeListener("chainChanged", onChainChanged);
425
424
  provider.removeListener("disconnect", onDisconnect);
426
425
  await provider.disconnect();
427
- cachedProvider = null;
428
426
  }
429
427
 
430
428
  function onDisconnect() {
@@ -438,7 +436,6 @@ function onConnect(
438
436
  if (accounts[0]) {
439
437
  const newAccount = createAccount({
440
438
  address: getAddress(accounts[0]),
441
- chain,
442
439
  client,
443
440
  provider,
444
441
  });
@@ -464,14 +461,66 @@ function onConnect(
464
461
  account,
465
462
  chain,
466
463
  disconnect,
467
- (newChain) => switchChainWC(provider, newChain),
464
+ (newChain) => switchChainWC(provider, newChain, storage),
468
465
  ];
469
466
  }
470
467
 
471
- async function switchChainWC(provider: WCProvider, chain: Chain) {
468
+ // Storage utils -----------------------------------------------------------------------------------------------
469
+
470
+ function getNamespaceMethods(provider: WCProvider) {
471
+ return provider.session?.namespaces[NAMESPACE]?.methods || [];
472
+ }
473
+
474
+ function getNamespaceChainsIds(provider: WCProvider): number[] {
475
+ const chainIds = provider.session?.namespaces[NAMESPACE]?.chains?.map(
476
+ (chain) => Number.parseInt(chain.split(":")[1] || ""),
477
+ );
478
+
479
+ return chainIds ?? [];
480
+ }
481
+
482
+ async function switchChainWC(
483
+ provider: WCProvider,
484
+ chain: Chain,
485
+ storage: AsyncStorage,
486
+ ) {
472
487
  const chainId = chain.id;
473
488
  try {
474
- provider.setDefaultChain(`eip155:${chainId}`);
489
+ const namespaceChains = getNamespaceChainsIds(provider);
490
+ const namespaceMethods = getNamespaceMethods(provider);
491
+ const isChainApproved = namespaceChains.includes(chainId);
492
+
493
+ if (!isChainApproved && namespaceMethods.includes(ADD_ETH_CHAIN_METHOD)) {
494
+ const apiChain = await getChainMetadata(chain);
495
+
496
+ const blockExplorerUrls = [
497
+ ...new Set([
498
+ ...(chain.blockExplorers?.map((x) => x.url) || []),
499
+ ...(apiChain.explorers?.map((x) => x.url) || []),
500
+ ]),
501
+ ];
502
+
503
+ await provider.request({
504
+ method: ADD_ETH_CHAIN_METHOD,
505
+ params: [
506
+ {
507
+ blockExplorerUrls:
508
+ blockExplorerUrls.length > 0 ? blockExplorerUrls : undefined,
509
+ chainId: numberToHex(apiChain.chainId),
510
+ chainName: apiChain.name,
511
+ nativeCurrency: apiChain.nativeCurrency, // no clientId on purpose
512
+ rpcUrls: getValidPublicRPCUrl(apiChain),
513
+ },
514
+ ],
515
+ });
516
+ const requestedChains = await getRequestedChainsIds(storage);
517
+ requestedChains.push(chainId);
518
+ setRequestedChainsIds(requestedChains, storage);
519
+ }
520
+ await provider.request({
521
+ method: "wallet_switchEthereumChain",
522
+ params: [{ chainId: numberToHex(chainId) }],
523
+ });
475
524
  } catch (error) {
476
525
  const message =
477
526
  typeof error === "string" ? error : (error as ProviderRpcError)?.message;
@@ -494,23 +543,35 @@ function setRequestedChainsIds(
494
543
  storage?.setItem(storageKeys.requestedChains, stringify(chains));
495
544
  }
496
545
 
546
+ /**
547
+ * Get the last requested chains from the storage.
548
+ * @internal
549
+ */
550
+ async function getRequestedChainsIds(storage: AsyncStorage): Promise<number[]> {
551
+ const data = await storage.getItem(storageKeys.requestedChains);
552
+ return data ? JSON.parse(data) : [];
553
+ }
554
+
555
+ type ArrayOneOrMore<T> = {
556
+ 0: T;
557
+ } & Array<T>;
558
+
497
559
  function getChainsToRequest(options: {
498
560
  chain?: Chain;
499
561
  optionalChains?: Chain[];
500
562
  client: ThirdwebClient;
501
563
  }): {
502
564
  rpcMap: Record<number, string>;
503
- chains: string[];
565
+ requiredChain: Chain | undefined;
566
+ optionalChains: ArrayOneOrMore<number>;
504
567
  } {
505
568
  const rpcMap: Record<number, string> = {};
506
- const chainIds: number[] = [];
507
569
 
508
570
  if (options.chain) {
509
571
  rpcMap[options.chain.id] = getRpcUrlForChain({
510
572
  chain: options.chain,
511
573
  client: options.client,
512
574
  });
513
- chainIds.push(options.chain.id);
514
575
  }
515
576
 
516
577
  // limit optional chains to 10
@@ -521,16 +582,18 @@ function getChainsToRequest(options: {
521
582
  chain: chain,
522
583
  client: options.client,
523
584
  });
524
- chainIds.push(chain.id);
525
585
  }
526
586
 
527
587
  if (!options.chain && optionalChains.length === 0) {
528
588
  rpcMap[1] = getCachedChain(1).rpc;
529
- chainIds.push(1);
530
589
  }
531
590
 
532
591
  return {
533
- chains: chainIds.map((x) => `eip155:${x}`),
592
+ optionalChains:
593
+ optionalChains.length > 0
594
+ ? (optionalChains.map((x) => x.id) as ArrayOneOrMore<number>)
595
+ : [1],
596
+ requiredChain: options.chain ? options.chain : undefined,
534
597
  rpcMap,
535
598
  };
536
599
  }