Skip to content

Commit 3edf931

Browse files
committed
feat: auto-login when connecting via url
1 parent c2acfd1 commit 3edf931

File tree

9 files changed

+101
-83
lines changed

9 files changed

+101
-83
lines changed

packages/thirdweb/src/react/core/hooks/connection/ConnectEmbedProps.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,11 @@ export type ConnectEmbedProps = {
289289
*/
290290
auth?: SiweAuthOptions;
291291

292+
/**
293+
* @hidden
294+
*/
295+
siweLogin?: () => Promise<void>;
296+
292297
/**
293298
* Customize the welcome screen. This prop is only applicable when modalSize prop is set to "wide". On "wide" Modal size, a welcome screen is shown on the right side of the modal.
294299
*

packages/thirdweb/src/react/native/ui/connect/ConnectButton.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ export function ConnectButton(props: ConnectButtonProps) {
4747
const status = useActiveWalletConnectionStatus();
4848
const connectionManager = useConnectionManager();
4949
const siweAuth = useSiweAuth(wallet, account, props.auth);
50-
useAutoConnect(props);
50+
useAutoConnect({
51+
...props,
52+
siweLogin: siweAuth.doLogin,
53+
});
5154

5255
const fadeAnim = useRef(new Animated.Value(0)); // For background opacity
5356
const slideAnim = useRef(new Animated.Value(screenHeight)); // For bottom sheet position

packages/thirdweb/src/react/web/ui/ConnectWallet/ConnectButton.tsx

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import { LockIcon } from "./icons/LockIcon.js";
3030
import { useConnectLocale } from "./locale/getConnectLocale.js";
3131
import type { ConnectLocale } from "./locale/types.js";
3232
import { SignatureScreen } from "./screens/SignatureScreen.js";
33-
import { useAdminWallet } from "src/exports/react.native.js";
3433

3534
const TW_CONNECT_WALLET = "tw-connect-wallet";
3635

@@ -298,6 +297,9 @@ export function ConnectButton(props: ConnectButtonProps) {
298297
);
299298
const localeQuery = useConnectLocale(props.locale || "en_US");
300299
const connectionManager = useConnectionManager();
300+
const activeAccount = useActiveAccount();
301+
const activeWallet = useActiveWallet();
302+
const siweAuth = useSiweAuth(activeWallet, activeAccount, props.auth);
301303

302304
usePreloadWalletProviders({
303305
wallets,
@@ -338,6 +340,7 @@ export function ConnectButton(props: ConnectButtonProps) {
338340
}
339341
accountAbstraction={props.accountAbstraction}
340342
onConnect={props.onConnect}
343+
siweLogin={siweAuth.doLogin}
341344
/>
342345
);
343346

@@ -363,7 +366,11 @@ export function ConnectButton(props: ConnectButtonProps) {
363366

364367
return (
365368
<WalletUIStatesProvider theme={props.theme} isOpen={false}>
366-
<ConnectButtonInner {...props} connectLocale={localeQuery.data} />
369+
<ConnectButtonInner
370+
{...props}
371+
siweAuth={siweAuth}
372+
connectLocale={localeQuery.data}
373+
/>
367374
<ConnectModal
368375
shouldSetActive={true}
369376
accountAbstraction={props.accountAbstraction}
@@ -397,12 +404,11 @@ export function ConnectButton(props: ConnectButtonProps) {
397404
function ConnectButtonInner(
398405
props: ConnectButtonProps & {
399406
connectLocale: ConnectLocale;
407+
siweAuth: ReturnType<typeof useSiweAuth>;
400408
},
401409
) {
402-
const activeWallet = useActiveWallet();
410+
const siweAuth = props.siweAuth;
403411
const activeAccount = useActiveAccount();
404-
const adminWallet = useAdminWallet();
405-
const siweAuth = useSiweAuth(activeWallet, activeAccount, props.auth);
406412
const [showSignatureModal, setShowSignatureModal] = useState(false);
407413

408414
// if wallet gets disconnected suddently, close the signature modal if it's open
@@ -412,28 +418,6 @@ function ConnectButtonInner(
412418
}
413419
}, [activeAccount]);
414420

415-
// if an IAW wallet is connected and auth is required, trigger a login attempt automatically
416-
useEffect(() => {
417-
const isIAW = activeWallet?.id === "inApp" || adminWallet?.id === "inApp";
418-
if (
419-
activeAccount &&
420-
siweAuth.requiresAuth &&
421-
!siweAuth.isLoggedIn &&
422-
!siweAuth.isLoggingIn &&
423-
isIAW
424-
) {
425-
siweAuth.doLogin();
426-
}
427-
}, [
428-
activeAccount,
429-
siweAuth.requiresAuth,
430-
siweAuth.doLogin,
431-
siweAuth.isLoggedIn,
432-
siweAuth.isLoggingIn,
433-
activeWallet,
434-
adminWallet,
435-
]);
436-
437421
const theme = props.theme || "dark";
438422
const connectionStatus = useActiveWalletConnectionStatus();
439423
const locale = props.connectLocale;

packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import {
1111
} from "../../../../core/design-system/CustomThemeProvider.js";
1212
import { radius } from "../../../../core/design-system/index.js";
1313
import {
14-
type SiweAuthOptions,
1514
useSiweAuth,
15+
type SiweAuthOptions,
1616
} from "../../../../core/hooks/auth/useSiweAuth.js";
1717
import type { ConnectEmbedProps } from "../../../../core/hooks/connection/ConnectEmbedProps.js";
1818
import { useActiveAccount } from "../../../../core/hooks/wallets/useActiveAccount.js";
@@ -247,6 +247,7 @@ export function ConnectEmbed(props: ConnectEmbedProps) {
247247
chain={preferredChain}
248248
appMetadata={props.appMetadata}
249249
client={props.client}
250+
siweLogin={siweAuth.doLogin}
250251
wallets={wallets}
251252
accountAbstraction={props.accountAbstraction}
252253
timeout={
@@ -326,21 +327,21 @@ const ConnectEmbedContent = (props: {
326327
};
327328
size: "compact" | "wide";
328329
header:
329-
| {
330-
title?: string;
331-
titleIcon?: string;
332-
}
333-
| true
334-
| undefined;
330+
| {
331+
title?: string;
332+
titleIcon?: string;
333+
}
334+
| true
335+
| undefined;
335336
localeId: LocaleId;
336337
onConnect: ((wallet: Wallet) => void) | undefined;
337338
recommendedWallets: Wallet[] | undefined;
338339
showAllWallets: boolean | undefined;
339340
walletConnect:
340-
| {
341-
projectId?: string;
342-
}
343-
| undefined;
341+
| {
342+
projectId?: string;
343+
}
344+
| undefined;
344345
wallets: Wallet[];
345346
welcomeScreen: WelcomeScreen | undefined;
346347
}) => {

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/OnRampScreen.tsx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@ import { sendTransaction } from "../../../../../../../transaction/actions/send-t
2323
import type { WaitForReceiptOptions } from "../../../../../../../transaction/actions/wait-for-tx-receipt.js";
2424
import { waitForReceipt } from "../../../../../../../transaction/actions/wait-for-tx-receipt.js";
2525
import { formatNumber } from "../../../../../../../utils/formatNumber.js";
26-
import { isEcosystemWallet } from "../../../../../../../wallets/ecosystem/is-ecosystem-wallet.js";
27-
import { isInAppWallet } from "../../../../../../../wallets/in-app/core/wallet/index.js";
28-
import type { Wallet } from "../../../../../../../wallets/interfaces/wallet.js";
29-
import { isSmartWallet } from "../../../../../../../wallets/smart/is-smart-wallet.js";
26+
import { isInAppSigner } from "../../../../../../../wallets/in-app/core/wallet/is-in-app-signer.js";
3027
import { spacing } from "../../../../../../core/design-system/index.js";
3128
import { useChainName } from "../../../../../../core/hooks/others/useChainQuery.js";
3229
import { useBuyWithCryptoStatus } from "../../../../../../core/hooks/pay/useBuyWithCryptoStatus.js";
@@ -779,20 +776,3 @@ function useSwapMutation(props: {
779776
},
780777
});
781778
}
782-
783-
function isInAppSigner(options: {
784-
wallet: Wallet;
785-
connectedWallets: Wallet[];
786-
}) {
787-
const isInAppOrEcosystem = (w: Wallet) =>
788-
isInAppWallet(w) || isEcosystemWallet(w);
789-
const isSmartWalletWithAdmin =
790-
isSmartWallet(options.wallet) &&
791-
options.connectedWallets.some(
792-
(w) =>
793-
isInAppOrEcosystem(w) &&
794-
w.getAccount()?.address?.toLowerCase() ===
795-
options.wallet.getAdminAccount?.()?.address?.toLowerCase(),
796-
);
797-
return isInAppOrEcosystem(options.wallet) || isSmartWalletWithAdmin;
798-
}

packages/thirdweb/src/react/web/ui/PayEmbed.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import type { AppMetadata } from "../../../wallets/types.js";
99
import type { WalletId } from "../../../wallets/wallet-types.js";
1010
import { CustomThemeProvider } from "../../core/design-system/CustomThemeProvider.js";
1111
import type { Theme } from "../../core/design-system/index.js";
12-
import type { SiweAuthOptions } from "../../core/hooks/auth/useSiweAuth.js";
12+
import {
13+
useSiweAuth,
14+
type SiweAuthOptions,
15+
} from "../../core/hooks/auth/useSiweAuth.js";
1316
import type {
1417
ConnectButton_connectModalOptions,
1518
PayUIOptions,
@@ -23,6 +26,9 @@ import { ExecutingTxScreen } from "./TransactionButton/ExecutingScreen.js";
2326
import { DynamicHeight } from "./components/DynamicHeight.js";
2427
import { Spinner } from "./components/Spinner.js";
2528
import type { LocaleId } from "./types.js";
29+
import { useActiveAccount } from "../../core/hooks/wallets/useActiveAccount.js";
30+
import { useActiveWallet } from "../../core/hooks/wallets/useActiveWallet.js";
31+
import { AutoConnect } from "../../web/ui/AutoConnect/AutoConnect.js";
2632

2733
/**
2834
* Props of [`PayEmbed`](https://portal.thirdweb.com/references/typescript/v5/PayEmbed) component
@@ -300,6 +306,13 @@ export function PayEmbed(props: PayEmbedProps) {
300306
const [screen, setScreen] = useState<"buy" | "execute-tx">("buy");
301307
const theme = props.theme || "dark";
302308
const connectionManager = useConnectionManager();
309+
const activeAccount = useActiveAccount();
310+
const activeWallet = useActiveWallet();
311+
const siweAuth = useSiweAuth(
312+
activeWallet,
313+
activeAccount,
314+
props.connectOptions?.auth,
315+
);
303316

304317
// Add props.chain and props.chains to defined chains store
305318
useEffect(() => {
@@ -342,6 +355,7 @@ export function PayEmbed(props: PayEmbedProps) {
342355
} else {
343356
content = (
344357
<>
358+
<AutoConnect client={props.client} siweLogin={siweAuth.doLogin} />
345359
{screen === "buy" && (
346360
<BuyScreen
347361
title={metadata?.name || "Buy"}
@@ -459,10 +473,10 @@ export type PayEmbedConnectOptions = {
459473
* ```
460474
*/
461475
autoConnect?:
462-
| {
463-
timeout: number;
464-
}
465-
| boolean;
476+
| {
477+
timeout: number;
478+
}
479+
| boolean;
466480

467481
/**
468482
* Metadata of the app that will be passed to connected wallet. Setting this is highly recommended.

packages/thirdweb/src/wallets/connection/autoConnectCore.ts

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -82,32 +82,32 @@ const _autoConnectCore = async ({
8282
getStoredActiveWalletId(storage),
8383
]);
8484

85-
const result = getUrlToken();
85+
const urlToken = getUrlToken();
8686

8787
// If an auth cookie is found and this site supports the wallet, we'll set the auth cookie in the client storage
88-
const wallet = wallets.find((w) => w.id === result?.walletId);
89-
if (result?.authCookie && wallet) {
88+
const wallet = wallets.find((w) => w.id === urlToken?.walletId);
89+
if (urlToken?.authCookie && wallet) {
9090
const clientStorage = new ClientScopedStorage({
9191
storage,
9292
clientId: props.client.clientId,
9393
ecosystem: isEcosystemWallet(wallet)
9494
? {
95-
id: wallet.id,
96-
partnerId: wallet.getConfig()?.partnerId,
97-
}
95+
id: wallet.id,
96+
partnerId: wallet.getConfig()?.partnerId,
97+
}
9898
: undefined,
9999
});
100-
await clientStorage.saveAuthCookie(result.authCookie);
100+
await clientStorage.saveAuthCookie(urlToken.authCookie);
101101
}
102-
if (result?.walletId) {
103-
lastActiveWalletId = result.walletId;
104-
lastConnectedWalletIds = lastConnectedWalletIds?.includes(result.walletId)
102+
if (urlToken?.walletId) {
103+
lastActiveWalletId = urlToken.walletId;
104+
lastConnectedWalletIds = lastConnectedWalletIds?.includes(urlToken.walletId)
105105
? lastConnectedWalletIds
106-
: [result.walletId, ...(lastConnectedWalletIds || [])];
106+
: [urlToken.walletId, ...(lastConnectedWalletIds || [])];
107107
}
108108

109-
if (result?.authProvider) {
110-
await setLastAuthProvider?.(result.authProvider, storage);
109+
if (urlToken?.authProvider) {
110+
await setLastAuthProvider?.(urlToken.authProvider, storage);
111111
}
112112

113113
// if no wallets were last connected or we didn't receive an auth token
@@ -132,7 +132,7 @@ const _autoConnectCore = async ({
132132
wallet: activeWallet,
133133
client: props.client,
134134
lastConnectedChain,
135-
authResult: result?.authResult,
135+
authResult: urlToken?.authResult,
136136
}),
137137
{
138138
ms: timeout,
@@ -150,9 +150,9 @@ const _autoConnectCore = async ({
150150
const connectedWallet = await (connectOverride
151151
? connectOverride(activeWallet)
152152
: manager.connect(activeWallet, {
153-
client: props.client,
154-
accountAbstraction: props.accountAbstraction,
155-
}));
153+
client: props.client,
154+
accountAbstraction: props.accountAbstraction,
155+
}));
156156
if (connectedWallet) {
157157
autoConnected = true;
158158
try {
@@ -183,13 +183,18 @@ const _autoConnectCore = async ({
183183
wallet,
184184
client: props.client,
185185
lastConnectedChain,
186-
authResult: result?.authResult,
186+
authResult: urlToken?.authResult,
187187
});
188188
manager.addConnectedWallet(wallet);
189189
} catch {
190190
// no-op
191191
}
192192
}
193+
194+
// Auto-login with SIWE
195+
if (urlToken && activeWallet && props.siweLogin) {
196+
await props.siweLogin();
197+
}
193198
manager.isAutoConnecting.setValue(false);
194199
return autoConnected; // useQuery needs a return value
195200
};

packages/thirdweb/src/wallets/connection/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,9 @@ export type AutoConnectProps = {
118118
* Callback to be called when the connection is timeout-ed
119119
*/
120120
onTimeout?: () => void;
121+
122+
/**
123+
* @hidden
124+
*/
125+
siweLogin?: () => Promise<void>;
121126
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { isEcosystemWallet } from "../../../../wallets/ecosystem/is-ecosystem-wallet.js";
2+
import type { Wallet } from "../../../interfaces/wallet.js";
3+
import { isSmartWallet } from "../../../smart/index.js";
4+
import { isInAppWallet } from "./index.js";
5+
6+
export function isInAppSigner(options: {
7+
wallet: Wallet;
8+
connectedWallets: Wallet[];
9+
}) {
10+
const isInAppOrEcosystem = (w: Wallet) =>
11+
isInAppWallet(w) || isEcosystemWallet(w);
12+
const isSmartWalletWithAdmin =
13+
isSmartWallet(options.wallet) &&
14+
options.connectedWallets.some(
15+
(w) =>
16+
isInAppOrEcosystem(w) &&
17+
w.getAccount()?.address?.toLowerCase() ===
18+
options.wallet.getAdminAccount?.()?.address?.toLowerCase(),
19+
);
20+
return isInAppOrEcosystem(options.wallet) || isSmartWalletWithAdmin;
21+
}

0 commit comments

Comments
 (0)