Skip to content

[SDK] Improve WalletConnect connection and auto-connection flow #7746

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fifty-bars-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---

Improve walletConnect connection and auto-connection flow
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { ThirdwebClient } from "../../../../client/client.js";
import { wait } from "../../../../utils/promise/wait.js";
import { formatWalletConnectUrl } from "../../../../utils/url.js";
import { isAndroid, isIOS, isMobile } from "../../../../utils/web/isMobile.js";
import { isMobile } from "../../../../utils/web/isMobile.js";
import { openWindow } from "../../../../utils/web/openWindow.js";
import type { WCSupportedWalletIds } from "../../../../wallets/__generated__/wallet-ids.js";
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
Expand Down Expand Up @@ -47,35 +47,23 @@
client: props.client,
walletConnect: {
onDisplayUri(uri) {
const preferNative =
walletInfo.mobile.native || walletInfo.mobile.universal;
try {
if (isMobile()) {
if (isAndroid()) {
if (preferNative) {
openWindow(
formatWalletConnectUrl(preferNative, uri).redirect,
);
}
} else if (isIOS()) {
if (preferNative) {
openWindow(
formatWalletConnectUrl(preferNative, uri).redirect,
);
}
const mobileAppLink =
walletInfo.mobile.native || walletInfo.mobile.universal;
if (mobileAppLink) {
openWindow(
formatWalletConnectUrl(mobileAppLink, uri).redirect,
);

Check warning on line 57 in packages/thirdweb/src/react/web/wallets/shared/WalletConnectConnection.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/wallets/shared/WalletConnectConnection.tsx#L52-L57

Added lines #L52 - L57 were not covered by tests
} else {
const preferUniversal =
walletInfo.mobile.universal || walletInfo.mobile.native;
if (preferUniversal) {
openWindow(
formatWalletConnectUrl(preferUniversal, uri).redirect,
);
}
// on android, wc:// links show the app picker
openWindow(uri);

Check warning on line 60 in packages/thirdweb/src/react/web/wallets/shared/WalletConnectConnection.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/wallets/shared/WalletConnectConnection.tsx#L60

Added line #L60 was not covered by tests
}
} else {
setQrCodeUri(uri);
}
} catch {
} catch (e) {
console.error(e);

Check warning on line 66 in packages/thirdweb/src/react/web/wallets/shared/WalletConnectConnection.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/wallets/shared/WalletConnectConnection.tsx#L65-L66

Added lines #L65 - L66 were not covered by tests
setErrorConnecting(true);
}
},
Expand Down Expand Up @@ -216,28 +204,7 @@
chain: props.chain,
client: props.client,
onDisplayUri(uri) {
const platformUris = {
android: walletInfo.mobile.universal || "",
ios: walletInfo.mobile.native || "",
other: walletInfo.mobile.universal || "",
};

setQrCodeUri(uri);
if (isMobile()) {
if (isAndroid()) {
openWindow(
`${platformUris.android}wc?uri=${encodeURIComponent(uri)}`,
);
} else if (isIOS()) {
openWindow(
`${platformUris.ios}wc?uri=${encodeURIComponent(uri)}`,
);
} else {
openWindow(
`${platformUris.other}wc?uri=${encodeURIComponent(uri)}`,
);
}
}
},
optionalChains: props.chains,
projectId: props.walletConnect?.projectId,
Expand All @@ -253,8 +220,6 @@
}
}, [
props.walletConnect,
walletInfo.mobile.native,
walletInfo.mobile.universal,
wallet,
props.chain,
props.client,
Expand Down
4 changes: 2 additions & 2 deletions packages/thirdweb/src/utils/web/isMobile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { detectOS } from "../detect-platform.js";
/**
* @internal
*/
export function isAndroid(): boolean {
function isAndroid(): boolean {
// can only detect if useragent is defined
if (typeof navigator === "undefined") {
return false;
Expand All @@ -15,7 +15,7 @@ export function isAndroid(): boolean {
/**
* @internal
*/
export function isIOS(): boolean {
function isIOS(): boolean {
// can only detect if useragent is defined
if (typeof navigator === "undefined") {
return false;
Expand Down
84 changes: 53 additions & 31 deletions packages/thirdweb/src/wallets/create-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import type { Chain } from "../chains/types.js";
import { getCachedChainIfExists } from "../chains/utils.js";
import { webLocalStorage } from "../utils/storage/webStorage.js";
import { formatWalletConnectUrl } from "../utils/url.js";
import { isMobile } from "../utils/web/isMobile.js";
import { openWindow } from "../utils/web/openWindow.js";
import { getWalletInfo } from "./__generated__/getWalletInfo.js";
import type {
InjectedSupportedWalletIds,
WCSupportedWalletIds,
Expand Down Expand Up @@ -313,43 +315,63 @@
...wcOptions,
walletConnect: {
...wcOptions.walletConnect,
onDisplayUri: wcOptions.walletConnect?.showQrModal
? async (uri) => {
// Check if we're in a browser environment
if (
typeof window !== "undefined" &&
typeof document !== "undefined"
) {
try {
const { createQROverlay } = await import(
"./wallet-connect/qr-overlay.js"
onDisplayUri:
wcOptions.walletConnect?.onDisplayUri ||
(async (uri) => {

Check warning on line 320 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L318-L320

Added lines #L318 - L320 were not covered by tests
// Check if we're in a browser environment
if (
typeof window !== "undefined" &&
typeof document !== "undefined"
) {

Check warning on line 325 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L322-L325

Added lines #L322 - L325 were not covered by tests
// on mobile, open the wallet app via deeplink
if (isMobile()) {
const walletInfo = await getWalletInfo(id);

Check warning on line 328 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L327-L328

Added lines #L327 - L328 were not covered by tests

const mobileAppLink =
walletInfo.mobile.native ||
walletInfo.mobile.universal;
if (mobileAppLink) {
openWindow(
formatWalletConnectUrl(mobileAppLink, uri)
.redirect,

Check warning on line 336 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L330-L336

Added lines #L330 - L336 were not covered by tests
);
} else {

Check warning on line 338 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L338

Added line #L338 was not covered by tests
// on android, wc:// links show the app picker
openWindow(uri);
}
return;
}

Check warning on line 343 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L340-L343

Added lines #L340 - L343 were not covered by tests

// Clean up any existing overlay
if (qrOverlay) {
qrOverlay.destroy();
}
try {

Check warning on line 345 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L345

Added line #L345 was not covered by tests
// on desktop, create a QR overlay
const { createQROverlay } = await import(
"./wallet-connect/qr-overlay.js"
);

Check warning on line 349 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L347-L349

Added lines #L347 - L349 were not covered by tests

// Create new QR overlay
qrOverlay = createQROverlay(uri, {
theme:
wcOptions.walletConnect?.qrModalOptions
?.themeMode ?? "dark",
qrSize: 280,
showCloseButton: true,
onCancel: () => {
wcOptions.walletConnect?.onCancel?.();
},
});
} catch (error) {
console.error(
"Failed to create QR overlay:",
error,
);
// Clean up any existing overlay
if (qrOverlay) {
qrOverlay.destroy();

Check warning on line 353 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L352-L353

Added lines #L352 - L353 were not covered by tests
}

// Create new QR overlay
qrOverlay = createQROverlay(uri, {
theme:
wcOptions.walletConnect?.qrModalOptions
?.themeMode ?? "dark",
qrSize: 280,
showCloseButton: true,
onCancel: () => {
wcOptions.walletConnect?.onCancel?.();
},
});
} catch (error) {
console.error(
"Failed to create QR overlay:",
error,
);

Check warning on line 371 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L357-L371

Added lines #L357 - L371 were not covered by tests
}
}
: undefined,
}),

Check warning on line 374 in packages/thirdweb/src/wallets/create-wallet.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/create-wallet.ts#L374

Added line #L374 was not covered by tests
},
},
emitter,
Expand Down
53 changes: 28 additions & 25 deletions packages/thirdweb/src/wallets/wallet-connect/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,30 +123,28 @@
optionalChains: optionalChains,
});

if (!provider.session) {
// For UniversalProvider, we need to connect with namespaces
await provider.connect({
...(wcOptions?.pairingTopic
? { pairingTopic: wcOptions?.pairingTopic }
: {}),
namespaces: {
[NAMESPACE]: {
chains: chainsToRequest,
events: ["chainChanged", "accountsChanged"],
methods: [
"eth_sendTransaction",
"eth_signTransaction",
"eth_sign",
"personal_sign",
"eth_signTypedData",
"wallet_switchEthereumChain",
"wallet_addEthereumChain",
],
rpcMap,
},
// For UniversalProvider, we need to connect with namespaces
await provider.connect({
...(wcOptions?.pairingTopic
? { pairingTopic: wcOptions?.pairingTopic }
: {}),
namespaces: {
[NAMESPACE]: {
chains: chainsToRequest,
events: ["chainChanged", "accountsChanged"],
methods: [
"eth_sendTransaction",
"eth_signTransaction",
"eth_sign",
"personal_sign",
"eth_signTypedData",
"wallet_switchEthereumChain",
"wallet_addEthereumChain",
],
rpcMap,

Check warning on line 144 in packages/thirdweb/src/wallets/wallet-connect/controller.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/wallet-connect/controller.ts#L127-L144

Added lines #L127 - L144 were not covered by tests
},
});
}
},
});

Check warning on line 147 in packages/thirdweb/src/wallets/wallet-connect/controller.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/wallet-connect/controller.ts#L146-L147

Added lines #L146 - L147 were not covered by tests

setRequestedChainsIds(
chainsToRequest.map((x) => Number(x.split(":")[1])),
Expand Down Expand Up @@ -223,9 +221,14 @@
sessionHandler,
);

if (!provider.session) {
await provider.disconnect();
throw new Error("No wallet connect session found on provider.");
}

Check warning on line 227 in packages/thirdweb/src/wallets/wallet-connect/controller.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/wallet-connect/controller.ts#L224-L227

Added lines #L224 - L227 were not covered by tests

// For UniversalProvider, get accounts from enable() method
const addresses = await provider.enable();
const address = addresses[0];
const namespaceAccounts = provider.session?.namespaces?.[NAMESPACE]?.accounts;
const address = namespaceAccounts?.[0]?.split(":")[2];

Check warning on line 231 in packages/thirdweb/src/wallets/wallet-connect/controller.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/wallet-connect/controller.ts#L230-L231

Added lines #L230 - L231 were not covered by tests

if (!address) {
throw new Error("No accounts found on provider.");
Expand Down
Loading