Skip to content

Commit 710ac32

Browse files
[SDK] Add WalletConnect deep linking support (#7772)
1 parent 6258f74 commit 710ac32

File tree

1 file changed

+96
-19
lines changed

1 file changed

+96
-19
lines changed

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

Lines changed: 96 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import type { UniversalProvider } from "@walletconnect/universal-provider";
1+
import type {
2+
RequestArguments,
3+
UniversalProvider,
4+
} from "@walletconnect/universal-provider";
25
import type { Address } from "abitype";
36
import {
47
getTypesForEIP712Domain,
@@ -39,6 +42,7 @@ import type { DisconnectFn, SwitchChainFn } from "../types.js";
3942
import { getDefaultAppMetadata } from "../utils/defaultDappMetadata.js";
4043
import { normalizeChainId } from "../utils/normalizeChainId.js";
4144
import type { WalletEmitter } from "../wallet-emitter.js";
45+
import type { WalletInfo } from "../wallet-info.js";
4246
import type { WalletId } from "../wallet-types.js";
4347
import { DEFAULT_PROJECT_ID, NAMESPACE } from "./constants.js";
4448
import type { WCAutoConnectOptions, WCConnectOptions } from "./types.js";
@@ -78,16 +82,16 @@ export async function connectWC(
7882
emitter: WalletEmitter<WCSupportedWalletIds>,
7983
walletId: WCSupportedWalletIds | "walletConnect",
8084
storage: AsyncStorage,
81-
sessionHandler?: (uri: string) => void,
85+
sessionHandler?: (uri: string) => void | Promise<void>,
8286
): Promise<ReturnType<typeof onConnect>> {
8387
const provider = await initProvider(options, walletId, sessionHandler);
8488
const wcOptions = options.walletConnect;
8589

8690
let { onDisplayUri } = wcOptions || {};
91+
const walletInfo = await getWalletInfo(walletId);
8792

8893
// use default sessionHandler unless onDisplayUri is explicitly provided
8994
if (!onDisplayUri && sessionHandler) {
90-
const walletInfo = await getWalletInfo(walletId);
9195
const deeplinkHandler = (uri: string) => {
9296
const appUrl = walletInfo.mobile.native || walletInfo.mobile.universal;
9397
if (!appUrl) {
@@ -185,7 +189,16 @@ export async function connectWC(
185189
provider.events.removeListener("display_uri", wcOptions.onDisplayUri);
186190
}
187191

188-
return onConnect(address, chain, provider, emitter, storage, options.client);
192+
return onConnect(
193+
address,
194+
chain,
195+
provider,
196+
emitter,
197+
storage,
198+
options.client,
199+
walletInfo,
200+
sessionHandler,
201+
);
189202
}
190203

191204
/**
@@ -197,12 +210,14 @@ export async function autoConnectWC(
197210
emitter: WalletEmitter<WCSupportedWalletIds>,
198211
walletId: WCSupportedWalletIds | "walletConnect",
199212
storage: AsyncStorage,
200-
sessionHandler?: (uri: string) => void,
213+
sessionHandler?: (uri: string) => void | Promise<void>,
201214
): Promise<ReturnType<typeof onConnect>> {
202215
const savedConnectParams: SavedConnectParams | null = storage
203216
? await getSavedConnectParamsFromStorage(storage, walletId)
204217
: null;
205218

219+
const walletInfo = await getWalletInfo(walletId);
220+
206221
const provider = await initProvider(
207222
savedConnectParams
208223
? {
@@ -243,7 +258,16 @@ export async function autoConnectWC(
243258
? options.chain
244259
: getCachedChain(providerChainId);
245260

246-
return onConnect(address, chain, provider, emitter, storage, options.client);
261+
return onConnect(
262+
address,
263+
chain,
264+
provider,
265+
emitter,
266+
storage,
267+
options.client,
268+
walletInfo,
269+
sessionHandler,
270+
);
247271
}
248272

249273
// Connection utils -----------------------------------------------------------------------------------------------
@@ -284,6 +308,10 @@ async function initProvider(
284308
],
285309
name: wcOptions?.appMetadata?.name || getDefaultAppMetadata().name,
286310
url: wcOptions?.appMetadata?.url || getDefaultAppMetadata().url,
311+
redirect: {
312+
native: walletInfo.mobile.native || undefined,
313+
universal: walletInfo.mobile.universal || undefined,
314+
},
287315
},
288316
projectId: wcOptions?.projectId || DEFAULT_PROJECT_ID,
289317
});
@@ -321,17 +349,22 @@ function createAccount({
321349
address,
322350
client,
323351
chain,
352+
sessionRequestHandler,
353+
walletInfo,
324354
}: {
325355
provider: WCProvider;
326356
address: string;
327357
client: ThirdwebClient;
328358
chain: Chain;
359+
sessionRequestHandler?: (uri: string) => void | Promise<void>;
360+
walletInfo: WalletInfo;
329361
}) {
330362
const account: Account = {
331363
address: getAddress(address),
332364
async sendTransaction(tx: SendTransactionOption) {
333-
const transactionHash = (await provider.request(
334-
{
365+
const transactionHash = (await requestAndOpenWallet({
366+
provider,
367+
payload: {
335368
method: "eth_sendTransaction",
336369
params: [
337370
{
@@ -343,8 +376,10 @@ function createAccount({
343376
},
344377
],
345378
},
346-
`eip155:${tx.chainId}`,
347-
)) as Hex;
379+
chain: `eip155:${tx.chainId}`,
380+
walletInfo,
381+
sessionRequestHandler,
382+
})) as Hex;
348383

349384
trackTransaction({
350385
chainId: tx.chainId,
@@ -370,13 +405,16 @@ function createAccount({
370405
}
371406
return message.raw;
372407
})();
373-
return provider.request(
374-
{
408+
return requestAndOpenWallet({
409+
provider,
410+
payload: {
375411
method: "personal_sign",
376412
params: [messageToSign, this.address],
377413
},
378-
`eip155:${chain.id}`,
379-
);
414+
chain: `eip155:${chain.id}`,
415+
walletInfo,
416+
sessionRequestHandler,
417+
});
380418
},
381419
async signTypedData(_data) {
382420
const data = parseTypedData(_data);
@@ -399,28 +437,65 @@ function createAccount({
399437
types,
400438
});
401439

402-
return await provider.request(
403-
{
440+
return await requestAndOpenWallet({
441+
provider,
442+
payload: {
404443
method: "eth_signTypedData_v4",
405444
params: [this.address, typedData],
406445
},
407-
`eip155:${chain.id}`,
408-
);
446+
chain: `eip155:${chain.id}`,
447+
walletInfo,
448+
sessionRequestHandler,
449+
});
409450
},
410451
};
411452

412453
return account;
413454
}
414455

456+
async function requestAndOpenWallet(args: {
457+
provider: WCProvider;
458+
payload: RequestArguments;
459+
chain?: string;
460+
walletInfo: WalletInfo;
461+
sessionRequestHandler?: (uri: string) => void | Promise<void>;
462+
}) {
463+
const { provider, payload, chain, walletInfo, sessionRequestHandler } = args;
464+
const resultPromise: Promise<`0x${string}`> = provider.request(
465+
payload,
466+
chain,
467+
);
468+
469+
const walletLinkToOpen =
470+
provider.session?.peer?.metadata?.redirect?.native ||
471+
walletInfo.mobile.native ||
472+
walletInfo.mobile.universal;
473+
474+
if (sessionRequestHandler && walletLinkToOpen) {
475+
await sessionRequestHandler(walletLinkToOpen);
476+
}
477+
478+
return resultPromise;
479+
}
480+
415481
function onConnect(
416482
address: string,
417483
chain: Chain,
418484
provider: WCProvider,
419485
emitter: WalletEmitter<WCSupportedWalletIds>,
420486
storage: AsyncStorage,
421487
client: ThirdwebClient,
488+
walletInfo: WalletInfo,
489+
sessionRequestHandler?: (uri: string) => void | Promise<void>,
422490
): [Account, Chain, DisconnectFn, SwitchChainFn] {
423-
const account = createAccount({ address, chain, client, provider });
491+
const account = createAccount({
492+
address,
493+
chain,
494+
client,
495+
provider,
496+
sessionRequestHandler,
497+
walletInfo,
498+
});
424499

425500
async function disconnect() {
426501
provider.removeListener("accountsChanged", onAccountsChanged);
@@ -444,6 +519,8 @@ function onConnect(
444519
chain,
445520
client,
446521
provider,
522+
sessionRequestHandler,
523+
walletInfo,
447524
});
448525
emitter.emit("accountChanged", newAccount);
449526
emitter.emit("accountsChanged", accounts);

0 commit comments

Comments
 (0)