Skip to content

Commit 51b9e6f

Browse files
Switch from EthereumProvider to UniversalProvider in WalletConnect
Co-authored-by: joaquim.verges <[email protected]>
1 parent e1e0487 commit 51b9e6f

File tree

4 files changed

+146
-152
lines changed

4 files changed

+146
-152
lines changed

packages/thirdweb/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"@tanstack/react-query": "5.81.5",
2626
"@thirdweb-dev/engine": "workspace:*",
2727
"@thirdweb-dev/insight": "workspace:*",
28-
"@walletconnect/ethereum-provider": "2.21.4",
28+
"@walletconnect/universal-provider": "2.21.4",
2929
"@walletconnect/sign-client": "2.20.1",
3030
"abitype": "1.0.8",
3131
"cross-spawn": "7.0.6",

packages/thirdweb/src/wallets/wallet-connect/controller.ts

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { EthereumProvider } from "@walletconnect/ethereum-provider";
1+
import type { UniversalProvider } from "@walletconnect/universal-provider";
22
import type { Address } from "abitype";
33
import {
44
getTypesForEIP712Domain,
@@ -48,7 +48,7 @@ import type { WalletId } from "../wallet-types.js";
4848
import { DEFAULT_PROJECT_ID, NAMESPACE } from "./constants.js";
4949
import type { WCAutoConnectOptions, WCConnectOptions } from "./types.js";
5050

51-
type WCProvider = InstanceType<typeof EthereumProvider>;
51+
type WCProvider = InstanceType<typeof UniversalProvider>;
5252

5353
type SavedConnectParams = {
5454
optionalChains?: Chain[];
@@ -58,7 +58,7 @@ type SavedConnectParams = {
5858

5959
const ADD_ETH_CHAIN_METHOD = "wallet_addEthereumChain";
6060

61-
const defaultShowQrModal = true;
61+
// const defaultShowQrModal = true; // Unused in UniversalProvider
6262

6363
const storageKeys = {
6464
lastUsedChainId: "tw.wc.lastUsedChainId",
@@ -123,24 +123,21 @@ export async function connectWC(
123123
}
124124
}
125125

126-
const {
127-
rpcMap,
128-
requiredChain,
129-
optionalChains: chainsToRequest,
130-
} = getChainsToRequest({
131-
chain: chainToRequest,
132-
client: options.client,
133-
optionalChains: optionalChains,
134-
});
126+
// For UniversalProvider, we still need chain configuration for session management
127+
const { requiredChain, optionalChains: chainsToRequest } = getChainsToRequest(
128+
{
129+
chain: chainToRequest,
130+
client: options.client,
131+
optionalChains: optionalChains,
132+
},
133+
);
135134

135+
// For UniversalProvider, we need to connect with namespaces
136136
if (provider.session) {
137137
await provider.connect({
138138
...(wcOptions?.pairingTopic
139139
? { pairingTopic: wcOptions?.pairingTopic }
140140
: {}),
141-
chains: requiredChain ? [requiredChain.id] : undefined,
142-
optionalChains: chainsToRequest,
143-
rpcMap: rpcMap,
144141
});
145142
}
146143

@@ -152,7 +149,9 @@ export async function connectWC(
152149
throw new Error("No accounts found on provider.");
153150
}
154151

155-
const providerChainId = normalizeChainId(provider.chainId);
152+
// For UniversalProvider, get chainId from the session namespaces
153+
const currentChainId = requiredChain?.id || chainsToRequest[0] || 1;
154+
const providerChainId = normalizeChainId(currentChainId);
156155

157156
const chain =
158157
options.chain && options.chain.id === providerChainId
@@ -212,13 +211,17 @@ export async function autoConnectWC(
212211
true, // is auto connect
213212
);
214213

215-
const address = provider.accounts[0];
214+
// For UniversalProvider, get accounts from enable() method
215+
const addresses = await provider.enable();
216+
const address = addresses[0];
216217

217218
if (!address) {
218219
throw new Error("No accounts found on provider.");
219220
}
220221

221-
const providerChainId = normalizeChainId(provider.chainId);
222+
// For UniversalProvider, get chainId from the session namespaces or use default
223+
const currentChainId = options.chain?.id || 1;
224+
const providerChainId = normalizeChainId(currentChainId);
222225

223226
const chain =
224227
options.chain && options.chain.id === providerChainId
@@ -238,8 +241,8 @@ async function initProvider(
238241
) {
239242
const walletInfo = await getWalletInfo(walletId);
240243
const wcOptions = options.walletConnect;
241-
const { EthereumProvider, OPTIONAL_EVENTS, OPTIONAL_METHODS } = await import(
242-
"@walletconnect/ethereum-provider"
244+
const { UniversalProvider } = await import(
245+
"@walletconnect/universal-provider"
243246
);
244247

245248
let optionalChains: Chain[] | undefined = wcOptions?.optionalChains;
@@ -253,19 +256,16 @@ async function initProvider(
253256
}
254257
}
255258

256-
const {
257-
rpcMap,
258-
requiredChain,
259-
optionalChains: chainsToRequest,
260-
} = getChainsToRequest({
261-
chain: chainToRequest,
262-
client: options.client,
263-
optionalChains: optionalChains,
264-
});
259+
// For UniversalProvider, chain configuration is handled during session establishment
260+
// const { requiredChain, optionalChains: chainsToRequest } = getChainsToRequest({
261+
// chain: chainToRequest,
262+
// client: options.client,
263+
// optionalChains: optionalChains,
264+
// });
265265

266-
const provider = await EthereumProvider.init({
267-
chains: requiredChain ? [requiredChain.id] : undefined,
268-
disableProviderPing: true,
266+
const provider = await UniversalProvider.init({
267+
projectId: wcOptions?.projectId || DEFAULT_PROJECT_ID,
268+
relayUrl: "wss://relay.walletconnect.com",
269269
metadata: {
270270
description:
271271
wcOptions?.appMetadata?.description ||
@@ -276,26 +276,13 @@ async function initProvider(
276276
name: wcOptions?.appMetadata?.name || getDefaultAppMetadata().name,
277277
url: wcOptions?.appMetadata?.url || getDefaultAppMetadata().url,
278278
},
279-
optionalChains: chainsToRequest,
280-
optionalEvents: OPTIONAL_EVENTS,
281-
optionalMethods: OPTIONAL_METHODS,
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,
291279
});
292280

293281
provider.events.setMaxListeners(Number.POSITIVE_INFINITY);
294282

295283
// disconnect the provider if chains are stale when (if not auto connecting)
296284
if (!isAutoConnect) {
297-
// const isStale = await isChainsStale(provider, chainsToRequest);
298-
285+
// For UniversalProvider, we handle disconnection differently
299286
if (provider.session) {
300287
await provider.disconnect();
301288
}
@@ -314,9 +301,10 @@ async function initProvider(
314301
}
315302
}
316303

317-
provider.signer.client.on("session_request_sent", handleSessionRequest);
304+
// For UniversalProvider, use different event handling
305+
provider.on("session_request_sent", handleSessionRequest);
318306
provider.events.addListener("disconnect", () => {
319-
provider.signer.client.off("session_request_sent", handleSessionRequest);
307+
provider.off("session_request_sent", handleSessionRequest);
320308
});
321309
}
322310

@@ -473,7 +461,7 @@ function getNamespaceMethods(provider: WCProvider) {
473461

474462
function getNamespaceChainsIds(provider: WCProvider): number[] {
475463
const chainIds = provider.session?.namespaces[NAMESPACE]?.chains?.map(
476-
(chain) => Number.parseInt(chain.split(":")[1] || ""),
464+
(chain: string) => Number.parseInt(chain.split(":")[1] || ""),
477465
);
478466

479467
return chainIds ?? [];

packages/thirdweb/src/wallets/wallet-connect/types.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
1-
import type { EthereumProvider } from "@walletconnect/ethereum-provider";
1+
// import type { UniversalProvider } from "@walletconnect/universal-provider"; // Types defined manually
22
import type { Chain } from "../../chains/types.js";
33
import type { ThirdwebClient } from "../../client/client.js";
44
import type { Prettify } from "../../utils/type-utils.js";
55
import type { AppMetadata } from "../types.js";
66

7-
type EthereumProviderOptions = Parameters<typeof EthereumProvider["init"]>[0];
7+
// For UniversalProvider, we need to define the options manually since it has a different API
8+
export type UniversalProviderOptions = {
9+
projectId: string;
10+
relayUrl?: string;
11+
metadata?: {
12+
name: string;
13+
description: string;
14+
url: string;
15+
icons: string[];
16+
};
17+
logger?: string;
18+
storage?: Record<string, unknown>;
19+
storageOptions?: Record<string, unknown>;
20+
};
821

9-
type WalletConnectQRCodeModalOptions = Pick<
10-
NonNullable<EthereumProviderOptions["qrModalOptions"]>,
11-
| "themeMode"
12-
| "themeVariables"
13-
| "desktopWallets"
14-
| "enableExplorer"
15-
| "explorerRecommendedWalletIds"
16-
| "explorerExcludedWalletIds"
17-
| "mobileWallets"
18-
| "privacyPolicyUrl"
19-
| "termsOfServiceUrl"
20-
| "walletImages"
21-
>;
22+
type WalletConnectQRCodeModalOptions = {
23+
themeMode?: "light" | "dark";
24+
themeVariables?: Record<string, string>;
25+
desktopWallets?: Record<string, unknown>[];
26+
enableExplorer?: boolean;
27+
explorerRecommendedWalletIds?: string[];
28+
explorerExcludedWalletIds?: string[];
29+
mobileWallets?: Record<string, unknown>[];
30+
privacyPolicyUrl?: string;
31+
termsOfServiceUrl?: string;
32+
walletImages?: Record<string, string>;
33+
};
2234

2335
export type WalletConnectConfig = {
2436
/**

0 commit comments

Comments
 (0)