[Refactor] Replace useApiAuthToken with useAccessToken (#3592)

<!-- start pr-codex -->

## PR-Codex overview
This PR enhances the `siwe_auth` functionality for better user authentication and access control.

### Detailed summary
- Renamed `ConnectWallet` component to `ConnectButton`
- Updated `useExtensionContractInfo` to use `useActiveAccount`
- Replaced `useApiAuthToken` with `useAccessToken` in multiple files
- Improved `useSiweAuth` with additional features and mutations
- Updated components to use `useAccessToken` for authentication
- Refactored `useLoggedInUser` to fetch user data efficiently

> The following files were skipped due to too many changes: `apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts`, `apps/dashboard/src/@3rdweb-sdk/react/components/connect-wallet/index.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
This commit is contained in:
jnsdls
2024-07-04 02:16:03 +00:00
parent eac126bb14
commit d2de83da66
16 changed files with 231 additions and 251 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---
make siwe_auth more robust
@@ -15,10 +15,75 @@ import Link from "next/link";
import { useCallback, useMemo } from "react";
import { defineChain } from "thirdweb";
import { ConnectButton, type SiweAuthOptions } from "thirdweb/react";
import { GLOBAL_AUTH_TOKEN_KEY } from "../../../../constants/app";
import { fetchAuthToken } from "../../hooks/useApi";
import { useFavoriteChains } from "../../hooks/useFavoriteChains";
import { fetchUserQuery } from "../../hooks/useLoggedInUser";
import { popularChains } from "../popularChains";
import { clearAccessToken, setAccessToken } from "./useAccessToken";
// TODO remove all of this
type FetchAuthTokenResponse = {
jwt: string;
};
const TOKEN_PROMISE_MAP = new Map<string, Promise<FetchAuthTokenResponse>>();
async function fetchAuthToken(
address: string,
abortController?: AbortController,
): Promise<FetchAuthTokenResponse> {
if (!address) {
throw new Error("address is required");
}
if (TOKEN_PROMISE_MAP.has(address)) {
return TOKEN_PROMISE_MAP.get(address) as Promise<FetchAuthTokenResponse>;
}
const promise = new Promise<FetchAuthTokenResponse>((resolve, reject) => {
return fetch(`${THIRDWEB_API_HOST}/v1/auth/token`, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
signal: abortController?.signal,
})
.then((res) => res.json())
.then((json) => {
if (json.error) {
throw new Error(json.error.message);
}
return {
jwt: json.data.jwt as string,
};
})
.then(resolve)
.catch(reject)
.finally(() => {
// remove the promise from the map when it's done
TOKEN_PROMISE_MAP.delete(address);
});
});
TOKEN_PROMISE_MAP.set(address, promise);
return promise;
}
// END TODO
export async function logout() {
// reset the token ASAP
clearAccessToken();
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/logout`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
throw new Error("Failed to logout");
}
return res.json();
}
export interface ConnectWalletProps {
shrinkMobile?: boolean;
@@ -99,49 +164,29 @@ export const CustomConnectWallet: React.FC<ConnectWalletProps> = ({
const json = await res.json();
if (json.token) {
// biome-ignore lint/suspicious/noExplicitAny: FIXME
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = json.token;
queryClient.invalidateQueries({
setAccessToken(json.token);
await queryClient.invalidateQueries({
queryKey: ["logged_in_user"],
});
}
return json;
},
doLogout: async () => {
// reset the token ASAP
// biome-ignore lint/suspicious/noExplicitAny: FIXME
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = undefined;
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/logout`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
const l = await logout();
await queryClient.invalidateQueries({
queryKey: ["logged_in_user"],
});
if (!res.ok) {
throw new Error("Failed to logout");
}
return res.json();
return l;
},
isLoggedIn: async (address) => {
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/user`, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
const user = await queryClient.fetchQuery(fetchUserQuery(address));
if (!user) {
return false;
}
const { jwt } = await fetchAuthToken(address);
if (jwt) {
// biome-ignore lint/suspicious/noExplicitAny: FIXME
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = jwt;
queryClient.invalidateQueries({
queryKey: ["logged_in_user"],
});
setAccessToken(jwt);
return true;
}
@@ -0,0 +1,42 @@
import { useSyncExternalStore } from "react";
// historical reasons
const GLOBAL_AUTH_TOKEN_KEY = "TW_AUTH_TOKEN";
let currentAccessToken: string | null = null;
let listeners: Array<() => void> = [];
const accessTokenStore = {
set: (value: string | null) => {
// also set it on window (because of legacy things reading from there)
// biome-ignore lint/suspicious/noExplicitAny: needed
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = value;
currentAccessToken = value;
for (const listener of listeners) {
listener();
}
},
getSnapshot: () => currentAccessToken,
subscribe: (listener: () => void) => {
listeners = [...listeners, listener];
return () => {
listeners = listeners.filter((l) => l !== listener);
};
},
};
export function setAccessToken(value: string) {
accessTokenStore.set(value);
}
export function clearAccessToken() {
accessTokenStore.set(null);
}
export function useAccessToken() {
return useSyncExternalStore(
accessTokenStore.subscribe,
accessTokenStore.getSnapshot,
// TODO: we should actually be able to grab this server side once we move auth to the next server
() => null,
);
}
@@ -5,7 +5,6 @@ import {
useQueryClient,
} from "@tanstack/react-query";
import type { Chain } from "@thirdweb-dev/chains";
import { useEffect, useState } from "react";
import invariant from "tiny-invariant";
import { THIRDWEB_API_HOST } from "../../../constants/urls";
import { accountKeys, apiKeys, authorizedWallets } from "../cache-keys";
@@ -953,114 +952,6 @@ export function useAuthorizedWallets() {
);
}
type FetchAuthTokenResponse = {
jwt: string;
paymentsSellerId?: string;
};
const TOKEN_PROMISE_MAP = new Map<string, Promise<FetchAuthTokenResponse>>();
export async function fetchAuthToken(
address: string,
abortController?: AbortController,
): Promise<FetchAuthTokenResponse> {
if (!address) {
throw new Error("address is required");
}
if (TOKEN_PROMISE_MAP.has(address)) {
return TOKEN_PROMISE_MAP.get(address) as Promise<FetchAuthTokenResponse>;
}
const promise = new Promise<FetchAuthTokenResponse>((resolve, reject) => {
return fetch(`${THIRDWEB_API_HOST}/v1/auth/token`, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
signal: abortController?.signal,
})
.then((res) => res.json())
.then((json) => {
if (json.error) {
throw new Error(json.error.message);
}
return {
jwt: json.data.jwt as string,
paymentsSellerId: json.data.paymentsSellerId,
};
})
.then(resolve)
.catch(reject)
.finally(() => {
// remove the promise from the map when it's done
TOKEN_PROMISE_MAP.delete(address);
});
});
TOKEN_PROMISE_MAP.set(address, promise);
return promise;
}
// keep the promise around so we don't fetch it multiple times even if the hook gets called from different places
let inflightPromise: Promise<FetchAuthTokenResponse> | null = null;
export function useApiAuthToken() {
const { user } = useLoggedInUser();
const [token, setToken] = useState<string | null>(null);
const [paymentsSellerId, setPaymentsSellerId] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
// not using a query because we don't want to store this in any cache
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
let mounted = true;
setError(null);
setIsLoading(false);
if (!user?.address) {
return;
}
setIsLoading(true);
const abortController = new AbortController();
if (!inflightPromise) {
inflightPromise = fetchAuthToken(user.address, abortController);
}
// eslint-disable-next-line promise/catch-or-return
inflightPromise
.then((t) => {
// eslint-disable-next-line promise/always-return
if (mounted) {
setToken(t.jwt);
if (t.paymentsSellerId) {
setPaymentsSellerId(t.paymentsSellerId);
}
}
})
.catch((err) => {
if (mounted) {
setError(err);
}
})
.finally(() => {
if (mounted) {
inflightPromise = null;
setIsLoading(false);
}
});
return () => {
mounted = false;
// cancel the fetch if it's still in flight
abortController.abort();
inflightPromise = null;
setToken(null);
};
}, [user?.address]);
return { error, isLoading, token, paymentsSellerId };
}
/**
*
*/
@@ -4,8 +4,8 @@ import { useState } from "react";
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
import invariant from "tiny-invariant";
import { engineKeys } from "../cache-keys";
import { useAccessToken } from "../components/connect-wallet/useAccessToken";
import { useMutationWithInvalidate } from "./query/useQueryWithNetwork";
import { useApiAuthToken } from "./useApi";
import { useLoggedInUser } from "./useLoggedInUser";
export function useEngineConnectedInstance() {
@@ -99,7 +99,7 @@ export type BackendWallet = {
};
export function useEngineBackendWallets(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
[engineKeys.backendWallets(instance)],
@@ -342,7 +342,7 @@ type TransactionResponse = {
* @returns
*/
export function useEngineTransactions(instance: string, autoUpdate: boolean) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.transactions(instance),
@@ -383,7 +383,7 @@ type WalletConfig =
};
export function useEngineWalletConfig(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.walletConfig(instance),
@@ -413,7 +413,7 @@ export function useEngineBackendWalletBalance(
instance: string,
address: string,
) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const chainId = useActiveWalletChain()?.id;
invariant(chainId, "chainId is required");
@@ -444,7 +444,7 @@ export type EngineAdmin = {
};
export function useEnginePermissions(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const address = useActiveAccount()?.address;
return useQuery(
@@ -479,7 +479,7 @@ export type AccessToken = {
};
export function useEngineAccessTokens(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.accessTokens(instance),
@@ -509,7 +509,7 @@ export type Keypair = {
};
export function useEngineKeypairs(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.keypairs(instance),
@@ -534,7 +534,7 @@ type AddKeypairInput = {
};
export function useEngineAddKeypair(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -567,7 +567,7 @@ type RemoveKeypairInput = {
};
export function useEngineRemoveKeypair(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -605,7 +605,7 @@ export type EngineRelayer = {
};
export function useEngineRelayer(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.relayers(instance),
@@ -632,7 +632,7 @@ export type CreateRelayerInput = {
};
export function useEngineCreateRelayer(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -665,7 +665,7 @@ type RevokeRelayerInput = {
};
export function useEngineRevokeRelayer(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -703,7 +703,7 @@ export type UpdateRelayerInput = {
};
export function useEngineUpdateRelayer(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -742,7 +742,7 @@ export interface EngineWebhook {
}
export function useEngineWebhooks(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.webhooks(instance),
@@ -781,7 +781,7 @@ export type SetWalletConfigInput =
};
export function useEngineSetWalletConfig(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -814,7 +814,7 @@ export type CreateBackendWalletInput = {
};
export function useEngineCreateBackendWallet(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -850,7 +850,7 @@ interface UpdateBackendWalletInput {
}
export function useEngineUpdateBackendWallet(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -901,7 +901,7 @@ export type ImportBackendWalletInput =
};
export function useEngineImportBackendWallet(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -932,7 +932,7 @@ export function useEngineImportBackendWallet(instance: string) {
}
export function useEngineGrantPermissions(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -965,7 +965,7 @@ type RevokePermissionsInput = {
};
export function useEngineRevokePermissions(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -998,7 +998,7 @@ type CreateAccessTokenResponse = AccessToken & {
};
export function useEngineCreateAccessToken(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -1031,7 +1031,7 @@ type RevokeAccessTokenInput = {
};
export function useEngineRevokeAccessToken(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -1065,7 +1065,7 @@ type UpdateAccessTokenInput = {
};
export function useEngineUpdateAccessToken(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -1100,7 +1100,7 @@ export type CreateWebhookInput = {
};
export function useEngineCreateWebhook(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -1133,7 +1133,7 @@ type RevokeWebhookInput = {
};
export function useEngineRevokeWebhook(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutationWithInvalidate(
@@ -1170,7 +1170,7 @@ type SendTokensInput = {
};
export function useEngineSendTokens(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useMutation(async (input: SendTokensInput) => {
invariant(instance, "instance is required");
@@ -1201,7 +1201,7 @@ export function useEngineSendTokens(instance: string) {
}
export function useEngineCorsConfiguration(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.corsUrls(instance),
@@ -1225,7 +1225,7 @@ interface SetCorsUrlInput {
export function useEngineSetCorsConfiguration(instance: string) {
const queryClient = useQueryClient();
const { token } = useApiAuthToken();
const token = useAccessToken();
return useMutation(
async (input: SetCorsUrlInput) => {
@@ -1268,7 +1268,7 @@ export interface EngineContractSubscription {
}
export function useEngineContractSubscription(instance: string) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.contractSubscriptions(instance),
async () => {
@@ -1298,7 +1298,7 @@ export interface AddContractSubscriptionInput {
export function useEngineAddContractSubscription(instance: string) {
const queryClient = useQueryClient();
const { token } = useApiAuthToken();
const token = useAccessToken();
return useMutation(
async (input: AddContractSubscriptionInput) => {
@@ -1333,7 +1333,7 @@ export interface RemoveContractSubscriptionInput {
export function useEngineRemoveContractSubscription(instance: string) {
const queryClient = useQueryClient();
const { token } = useApiAuthToken();
const token = useAccessToken();
return useMutation(
async (input: RemoveContractSubscriptionInput) => {
@@ -1367,7 +1367,7 @@ export function useEngineSubscriptionsLastBlock(
chainId: number,
autoUpdate: boolean,
) {
const { token } = useApiAuthToken();
const token = useAccessToken();
return useQuery(
engineKeys.contractSubscriptionsLastBlock(instanceUrl, chainId),
@@ -1,22 +1,13 @@
import { useQuery } from "@tanstack/react-query";
import type { UserWithData } from "@thirdweb-dev/react";
import { THIRDWEB_API_HOST } from "constants/urls";
import { useMemo } from "react";
import { getAddress } from "thirdweb";
import {
useActiveAccount,
useActiveWalletConnectionStatus,
} from "thirdweb/react";
import { useActiveAccount } from "thirdweb/react";
export function useLoggedInUser(): {
isLoading: boolean;
isLoggedIn: boolean;
user: UserWithData | null;
} {
const connectedAddress = useActiveAccount()?.address;
const connectionStatus = useActiveWalletConnectionStatus();
const userQuery = useQuery({
queryKey: ["logged_in_user"],
export function fetchUserQuery(address: string) {
return {
enabled: !!address,
queryKey: ["logged_in_user", address],
queryFn: async () => {
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/user`, {
method: "GET",
@@ -25,45 +16,48 @@ export function useLoggedInUser(): {
"Content-Type": "application/json",
},
});
return (await res.json()) as UserWithData | null;
},
enabled: !!connectedAddress,
});
return useMemo(() => {
switch (connectionStatus) {
case "disconnected": {
return {
user: null,
isLoading: false,
isLoggedIn: false,
};
if (!res.ok) {
throw new Error("Failed to fetch user data");
}
case "connected": {
if (
connectedAddress &&
userQuery.data?.address &&
getAddress(connectedAddress) !== getAddress(userQuery.data?.address)
) {
return {
user: null,
isLoading: userQuery.isLoading,
isLoggedIn: false,
};
try {
const json = await res.json();
if (json === null) {
throw new Error("Failed to fetch user data");
}
return {
user: userQuery.data ?? null,
isLoading: userQuery.isLoading,
isLoggedIn: !!userQuery.data,
};
const user = json as UserWithData;
if (user && getAddress(user.address) === getAddress(address)) {
return user;
}
throw new Error("Failed to fetch user data");
} catch {
throw new Error("Failed to fetch user data");
}
case "connecting": {
return {
user: null,
isLoading: true,
isLoggedIn: false,
};
}
}
}, [connectionStatus, userQuery.data, userQuery.isLoading, connectedAddress]);
},
refetchOnWindowFocus: false,
refetchOnMount: false,
} as const;
}
export function useLoggedInUser(): {
isLoading: boolean;
isLoggedIn: boolean;
user: UserWithData | null;
} {
const connectedAddress = useActiveAccount()?.address;
const query = useQuery(fetchUserQuery(connectedAddress || ""));
if (query.fetchStatus === "fetching") {
return {
isLoading: true,
isLoggedIn: false,
user: null,
};
}
return {
isLoading: query.isLoading,
isLoggedIn: query.isSuccess ? !!query.data : false,
user: query.isSuccess ? query.data : null,
};
}
@@ -1,4 +1,3 @@
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
import {
type EditEngineInstanceInput,
type EngineInstance,
@@ -46,6 +45,7 @@ import { BiPencil } from "react-icons/bi";
import { FiArrowRight, FiTrash } from "react-icons/fi";
import { useActiveAccount } from "thirdweb/react";
import { Badge, Button, FormLabel, Heading, Text } from "tw-components";
import { useAccessToken } from "../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
interface EngineInstancesTableProps {
instances: EngineInstance[];
@@ -65,7 +65,7 @@ export const EngineInstancesTable: React.FC<EngineInstancesTableProps> = ({
const editDisclosure = useDisclosure();
const removeDisclosure = useDisclosure();
const trackEvent = useTrack();
const { token } = useApiAuthToken();
const token = useAccessToken();
const address = useActiveAccount()?.address;
const toast = useToast();
@@ -2,8 +2,8 @@ import { Box, DarkMode } from "@chakra-ui/react";
import { ClientOnly } from "components/ClientOnly/ClientOnly";
import "../../../css/swagger-ui.css";
import "swagger-ui-react/swagger-ui.css";
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
import dynamic from "next/dynamic";
import { useAccessToken } from "../../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
const SwaggerUI = dynamic(() => import("swagger-ui-react"), { ssr: false });
@@ -14,7 +14,7 @@ interface EngineExplorerProps {
export const EngineExplorer: React.FC<EngineExplorerProps> = ({
instanceUrl,
}) => {
const { token } = useApiAuthToken();
const token = useAccessToken();
return (
<ClientOnly ssr={null}>
<DarkMode>
@@ -1,4 +1,3 @@
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
import type { Transaction } from "@3rdweb-sdk/react/hooks/useEngine";
import {
Flex,
@@ -23,6 +22,7 @@ import { useRef } from "react";
import { FiCheck } from "react-icons/fi";
import { Button, FormLabel, Text } from "tw-components";
import { AddressCopyButton } from "tw-components/AddressCopyButton";
import { useAccessToken } from "../../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
interface TimelineStep {
step: string;
@@ -182,7 +182,7 @@ const CancelTransactionButton = ({
instanceUrl: string;
}) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const auth = useApiAuthToken();
const token = useAccessToken();
const { onSuccess, onError } = useTxNotifications(
"Successfully sent a request to cancel the transaction",
"Failed to cancel transaction",
@@ -195,7 +195,7 @@ const CancelTransactionButton = ({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${auth.token}`,
Authorization: `Bearer ${token}`,
"x-backend-wallet-address": transaction.fromAddress ?? "",
},
body: JSON.stringify({ queueId: transaction.queueId }),
@@ -1,9 +1,10 @@
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
import { Flex, FocusLock, VStack } from "@chakra-ui/react";
import { useDisconnect, useLogout } from "@thirdweb-dev/react";
import { AccountForm } from "components/settings/Account/AccountForm";
import { useState } from "react";
import { useActiveWallet, useDisconnect } from "thirdweb/react";
import { Button } from "tw-components";
import { logout } from "../../@3rdweb-sdk/react/components/connect-wallet";
import { OnboardingTitle } from "./Title";
type OnboardingGeneralProps = {
@@ -17,14 +18,16 @@ export const OnboardingGeneral: React.FC<OnboardingGeneralProps> = ({
onSave,
onDuplicate,
}) => {
const { logout } = useLogout();
const [existing, setExisting] = useState(false);
const disconnect = useDisconnect();
const activeWallet = useActiveWallet();
const { disconnect } = useDisconnect();
const handleLogout = async () => {
await logout();
disconnect();
};
async function handleDisconnect() {
if (activeWallet) {
await logout();
disconnect(activeWallet);
}
}
return (
<FocusLock>
@@ -68,7 +71,7 @@ export const OnboardingGeneral: React.FC<OnboardingGeneralProps> = ({
</Button>
<Button
variant="link"
onClick={handleLogout}
onClick={handleDisconnect}
w="full"
size="sm"
pt={4}
@@ -1,4 +1,3 @@
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
import { Center, Flex, Tooltip } from "@chakra-ui/react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
@@ -9,6 +8,7 @@ import { DASHBOARD_STORAGE_URL } from "lib/sdk";
import { useCallback, useState } from "react";
import { Button, Card, Heading, Text, TrackedCopyButton } from "tw-components";
import { toSize } from "utils/number";
import { useAccessToken } from "../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
interface PinnedFilesResponse {
result: PinnedFilesResult;
@@ -37,7 +37,7 @@ function usePinnedFilesQuery({
pageSize: number;
}) {
const user = useLoggedInUser();
const { token } = useApiAuthToken();
const token = useAccessToken();
const offset = page * pageSize;
@@ -76,7 +76,7 @@ function usePinnedFilesQuery({
}
function useUnpinFileMutation() {
const { token } = useApiAuthToken();
const token = useAccessToken();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ cid }: { cid: string }) => {
-3
View File
@@ -1,9 +1,6 @@
import { isBrowser } from "../utils/isBrowser";
export const GLOBAL_AUTH_TOKEN_KEY = "TW_AUTH_TOKEN";
// EWS token shenaningans
const GLOBAL_EWS_AUTH_TOKEN_KEY = "TW_EWS_AUTH_TOKEN";
export function storeEWSToken(token: string): void {
@@ -268,7 +268,7 @@ import { ThirdwebProvider, ConnectButton } from "thirdweb/react";
export default function App() {
return (
<ThirdwebProvider>
<ConnectWallet
<ConnectButton
client={client}
accountAbstraction={{
chain: defineChain({{chainId}}),
@@ -1,11 +1,11 @@
import { useEVMContractInfo } from "@3rdweb-sdk/react";
import { useAddress } from "@thirdweb-dev/react";
import { usePublishedContractsFromDeploy } from "components/contract-components/hooks";
import { THIRDWEB_DEPLOYER_ADDRESS } from "constants/addresses";
import { useMemo } from "react";
import { useActiveAccount } from "thirdweb/react";
export function useExtensionContractInfo(contractAddress: string) {
const address = useAddress();
const address = useActiveAccount()?.address;
const activeNetworkInfo = useEVMContractInfo();
const publishedContractsFromDeploy = usePublishedContractsFromDeploy(
@@ -66,10 +66,12 @@ export function useSiweAuth(
}
return authOptions.isLoggedIn(activeAccount.address);
},
placeholderData: false,
refetchOnWindowFocus: false,
});
const loginMutation = useMutation({
mutationKey: ["siwe_auth", "login"],
mutationFn: async () => {
if (!authOptions) {
throw new Error("No auth options provided");
@@ -109,6 +111,7 @@ export function useSiweAuth(
});
const logoutMutation = useMutation({
mutationKey: ["siwe_auth", "logout"],
mutationFn: async () => {
if (!authOptions) {
throw new Error("No auth options provided");
@@ -137,6 +140,6 @@ export function useSiweAuth(
// checking if logged in
isLoggedIn: isLoggedInQuery.data,
isLoading: isLoggedInQuery.isLoading,
isLoading: isLoggedInQuery.isFetching,
};
}
@@ -222,7 +222,7 @@ function ConnectButtonInner(
if (siweAuth.requiresAuth) {
// loading state if loading
// TODO: figure out a way to consolidate the loading states with the ones from locale loading
if (siweAuth.isLoading) {
if (siweAuth.isLoading || siweAuth.isLoggingIn || siweAuth.isLoggingOut) {
return (
<AnimatedButton
disabled={true}