Skip to content

Commit e1bd68f

Browse files
committed
fix race condition with WalletConnect init finishing before sessions init
1 parent eee1ecc commit e1bd68f

File tree

6 files changed

+53
-29
lines changed

6 files changed

+53
-29
lines changed

.changeset/six-laws-see.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@turnkey/core": minor
3+
---
4+
5+
- Parallelized stamper and session initialization
6+
- Separated WalletConnect initialization from client init
7+
- Optimized `fetchWallet` by reducing redundant queries and running wallet/user fetches in parallel
8+
- Added optional `authenticatorAddresses` param to `fetchWalletAccounts()`
9+
- Updated to latest `@walletconnect/sign-client` for performance improvements

.changeset/wild-monkeys-report.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@turnkey/react-wallet-kit": minor
3+
---
4+
5+
- Fixed unnecessary re-renders by ensuring all `useCallback` hooks include only direct dependencies
6+
- ConnectWallet and Auth model updated to show WalletConnect loading state during initialization

packages/react-wallet-kit/src/components/auth/Wallet.tsx

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,29 @@ const canDisconnect = (
6060
);
6161
};
6262

63+
interface ExternalWalletChainSelectorProps {
64+
providers: WalletProvider[];
65+
onDisconnect?: ((provider: WalletProvider) => Promise<void>) | undefined;
66+
onSelect: (provider: WalletProvider) => Promise<void>;
67+
}
6368
export function ExternalWalletChainSelector(
64-
props: ExternalWalletSelectorProps,
69+
props: ExternalWalletChainSelectorProps,
6570
) {
6671
const { providers, onSelect, onDisconnect } = props;
6772

6873
const { walletProviders } = useTurnkey();
6974
const { isMobile, closeModal } = useModal();
7075

7176
// we find matching providers in current state
72-
const currentProviders = providers.map((inputProvider) =>
73-
walletProviders.find(
74-
(p) =>
75-
p.interfaceType === inputProvider.interfaceType &&
76-
p.chainInfo.namespace === inputProvider.chainInfo.namespace,
77-
),
78-
).filter((p): p is WalletProvider => p !== undefined);
77+
const currentProviders = providers
78+
.map((inputProvider) =>
79+
walletProviders.find(
80+
(p) =>
81+
p.interfaceType === inputProvider.interfaceType &&
82+
p.chainInfo.namespace === inputProvider.chainInfo.namespace,
83+
),
84+
)
85+
.filter((p): p is WalletProvider => p !== undefined);
7986

8087
// if no providers are found then that means that the user entered this screen
8188
// while WalletConnect was still initializing, and then it failed to initialize
@@ -182,18 +189,19 @@ export function ExternalWalletChainSelector(
182189
}
183190

184191
interface ExternalWalletSelectorProps {
185-
providers: WalletProvider[];
186192
onDisconnect?: ((provider: WalletProvider) => Promise<void>) | undefined;
187193
onSelect: (provider: WalletProvider) => Promise<void>;
188194
}
189195
export function ExternalWalletSelector(props: ExternalWalletSelectorProps) {
190-
const { providers, onDisconnect, onSelect } = props;
196+
const { onDisconnect, onSelect } = props;
197+
191198
const { pushPage, popPage, isMobile } = useModal();
199+
const { walletProviders } = useTurnkey();
192200

193201
const shouldShowDisconnect = onDisconnect !== undefined;
194202

195203
// Group providers by name
196-
const grouped = providers.reduce<Record<string, WalletProvider[]>>(
204+
const grouped = walletProviders.reduce<Record<string, WalletProvider[]>>(
197205
(acc, provider) => {
198206
const name = provider.info.name;
199207
if (!acc[name]) acc[name] = [];
@@ -430,7 +438,6 @@ function QRCodeDisplay(props: QRCodeDisplayProps) {
430438

431439
return (
432440
<div className="relative inline-block">
433-
{/* @ts-expect-error: qrcode.react uses a different React type version */}
434441
<QRCode
435442
className={clsx(
436443
"block border border-modal-background-dark/20 dark:border-modal-background-light/20",
@@ -499,7 +506,7 @@ export function WalletConnectScreen(props: WalletConnectScreenProps) {
499506
}
500507
}, [provider, closeModal]);
501508

502-
const connectedAccount = provider?.connectedAddresses?.[0] ?? null;
509+
const connectedAccount = provider?.connectedAddresses?.[0] ?? null;
503510

504511
// Initial connection effect
505512
useEffect(() => {

packages/react-wallet-kit/src/components/auth/index.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export function AuthComponent({
4444
const {
4545
config,
4646
clientState,
47-
walletProviders,
4847
handleGoogleOauth,
4948
handleAppleOauth,
5049
handleFacebookOauth,
@@ -325,12 +324,7 @@ export function AuthComponent({
325324
try {
326325
pushPage({
327326
key: "Select wallet provider",
328-
content: (
329-
<ExternalWalletSelector
330-
providers={walletProviders}
331-
onSelect={handleSelect}
332-
/>
333-
),
327+
content: <ExternalWalletSelector onSelect={handleSelect} />,
334328
});
335329
} catch (error) {
336330
throw new Error(`Error fetching wallet providers: ${error}`);

packages/react-wallet-kit/src/components/user/ConnectWallet.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ import {
1616
import { isWalletConnect } from "../../utils/utils";
1717

1818
interface ConnectWalletModalProps {
19-
providers: WalletProvider[];
2019
successPageDuration?: number | undefined;
2120
onSuccess: (type: "connect" | "disconnect", account: WalletAccount) => void;
2221
}
2322
export function ConnectWalletModal(props: ConnectWalletModalProps) {
24-
const { providers, successPageDuration, onSuccess } = props;
23+
const { successPageDuration, onSuccess } = props;
2524
const { pushPage, closeModal } = useModal();
2625
const { wallets, connectWalletAccount, disconnectWalletAccount } =
2726
useTurnkey();
@@ -132,7 +131,6 @@ export function ConnectWalletModal(props: ConnectWalletModalProps) {
132131
};
133132
return (
134133
<ExternalWalletSelector
135-
providers={providers}
136134
onSelect={handleConnectWallet}
137135
onDisconnect={handleDisconnectWallet}
138136
/>

packages/react-wallet-kit/src/providers/client/Provider.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,19 @@ export const ClientProvider: React.FC<ClientProviderProps> = ({
843843
return;
844844
}
845845
setSession(allLocalStorageSessions[activeSessionKey]);
846-
await Promise.all([refreshUser(), refreshWallets()]);
846+
847+
// we use `fetchWallets()` instead of `refreshWallets()` here to avoid a race condition
848+
// specifically, if WalletConnect finishes initializing before this promise resolves,
849+
// `refreshWallets()` could overwrite the WalletConnect wallet state with an outdated
850+
// list of wallets that doesn’t yet include the WalletConnect wallets
851+
const [, wallets] = await Promise.all([refreshUser(), fetchWallets()]);
852+
853+
// the prev wallets should only ever be WalletConnect wallets
854+
if (wallets) {
855+
setWallets((prev) => [...prev, ...wallets]);
856+
}
857+
858+
console.log("finished fetching wallets inside initializeSessions");
847859

848860
return;
849861
}
@@ -1013,8 +1025,9 @@ export const ClientProvider: React.FC<ClientProviderProps> = ({
10131025

10141026
// if we have an active session, we need to restore any possibly connected
10151027
// WalletConnect wallets since its now initialized
1016-
if (session) {
1017-
const wcProviders = providers.filter(
1028+
const currentSession = await getSession();
1029+
if (currentSession) {
1030+
const wcProviders = providers?.filter(
10181031
(p) => p.interfaceType === WalletInterfaceType.WalletConnect,
10191032
);
10201033

@@ -5277,14 +5290,11 @@ export const ClientProvider: React.FC<ClientProviderProps> = ({
52775290
);
52785291
}
52795292

5280-
const providers = await fetchWalletProviders();
5281-
52825293
return new Promise((resolve, reject) => {
52835294
pushPage({
52845295
key: "Connect wallet",
52855296
content: (
52865297
<ConnectWalletModal
5287-
providers={providers}
52885298
successPageDuration={successPageDuration}
52895299
onSuccess={(
52905300
type: "connect" | "disconnect",

0 commit comments

Comments
 (0)