Skip to content
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
1 change: 1 addition & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"next-plausible": "^3.12.4",
"next-themes": "^0.4.4",
"nextjs-toploader": "^1.6.12",
"nuqs": "^2.4.0",
"p-limit": "^6.2.0",
"papaparse": "^5.5.2",
"pluralize": "^8.0.0",
Expand Down
9 changes: 0 additions & 9 deletions apps/dashboard/src/@/actions/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,6 @@ async function proxy<T extends object>(
};
}

export async function analyticsServerProxy<T extends object = object>(
params: ProxyActionParams,
) {
return proxy<T>(
process.env.ANALYTICS_SERVICE_URL || "https://analytics.thirdweb.com",
params,
);
}

export async function apiServerProxy<T extends object = object>(
params: ProxyActionParams,
) {
Expand Down
48 changes: 43 additions & 5 deletions apps/dashboard/src/@/api/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
WalletStats,
WalletUserStats,
} from "types/analytics";
import { getChains } from "./chain";

function buildSearchParams(
params: AnalyticsQueryParams | AnalyticsQueryParamsV2,
Expand Down Expand Up @@ -93,13 +94,16 @@ export async function getInAppWalletUsage(
}

export async function getUserOpUsage(
params: AnalyticsQueryParams,
params: AnalyticsQueryParamsV2,
): Promise<UserOpStats[]> {
const searchParams = buildSearchParams(params);
const res = await fetchAnalytics(`v1/user-ops?${searchParams.toString()}`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
const res = await fetchAnalytics(
`v2/bundler/usage?${searchParams.toString()}`,
{
method: "GET",
headers: { "Content-Type": "application/json" },
},
);

if (res?.status !== 200) {
const reason = await res?.text();
Expand All @@ -113,6 +117,40 @@ export async function getUserOpUsage(
return json.data as UserOpStats[];
}

export async function getAggregateUserOpUsage(
params: Omit<AnalyticsQueryParamsV2, "period">,
): Promise<UserOpStats> {
const [userOpStats, chains] = await Promise.all([
getUserOpUsage({ ...params, period: "all" }),
getChains(),
]);
// Aggregate stats across wallet types
return userOpStats.reduce(
(acc, curr) => {
// Skip testnets from the aggregated stats
if (curr.chainId) {
const chain = chains.data.find(
(c) => c.chainId.toString() === curr.chainId,
);
if (chain?.testnet) {
return acc;
}
}

acc.successful += curr.successful;
acc.failed += curr.failed;
acc.sponsoredUsd += curr.sponsoredUsd;
return acc;
},
{
date: (params.from || new Date()).toISOString(),
successful: 0,
failed: 0,
sponsoredUsd: 0,
},
);
}

export async function getClientTransactions(
params: AnalyticsQueryParamsV2,
): Promise<TransactionStats[]> {
Expand Down
20 changes: 20 additions & 0 deletions apps/dashboard/src/@/api/chain.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import "server-only";
import type { ChainMetadata } from "thirdweb/chains";
import type { ChainService } from "../../app/(dashboard)/(chain)/types/chain";
import { API_SERVER_URL, THIRDWEB_API_SECRET } from "../constants/env";

export async function getGasSponsoredChains() {
Expand Down Expand Up @@ -32,3 +34,21 @@ export async function getGasSponsoredChains() {
return [];
}
}

export function getChains() {
return fetch(
`${API_SERVER_URL}/v1/chains`,
// revalidate every 60 minutes
{ next: { revalidate: 60 * 60 } },
).then((res) => res.json()) as Promise<{ data: ChainMetadata[] }>;
}

export function getChainServices() {
return fetch(
`${API_SERVER_URL}/v1/chains/services`,
// revalidate every 60 minutes
{ next: { revalidate: 60 * 60 } },
).then((res) => res.json()) as Promise<{
data: Record<number, Array<ChainService>>;
}>;
}
130 changes: 1 addition & 129 deletions apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { analyticsServerProxy, apiServerProxy } from "@/actions/proxies";
import { apiServerProxy } from "@/actions/proxies";
import type { Project } from "@/api/projects";
import type { Team } from "@/api/team";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useAllChainsData } from "hooks/chains/allChains";
import { useActiveAccount } from "thirdweb/react";
import type { UserOpStats } from "types/analytics";
import { accountKeys, authorizedWallets } from "../cache-keys";

// FIXME: We keep repeating types, API server should provide them
Expand Down Expand Up @@ -142,132 +140,6 @@ export function useAccountCredits() {
});
}

type UserOpUsageQueryResult = (UserOpStats & { chainId?: string })[];

async function getUserOpUsage(args: {
clientId: string;
from?: Date;
to?: Date;
period?: "day" | "week" | "month" | "year" | "all";
}) {
const { clientId, from, to, period } = args;

const searchParams: Record<string, string> = {
clientId,
};

if (from) {
searchParams.from = from.toISOString();
}
if (to) {
searchParams.to = to.toISOString();
}
if (period) {
searchParams.period = period;
}

const res = await analyticsServerProxy<{ data: UserOpUsageQueryResult }>({
pathname: "/v1/user-ops",
method: "GET",
searchParams: searchParams,
headers: {
"Content-Type": "application/json",
},
});

if (!res.ok) {
throw new Error(res.error);
}

const json = res.data;

return json.data;
}

// TODO - remove this hook, fetch this on server
export function useUserOpUsageAggregate(args: {
clientId: string;
from?: Date;
to?: Date;
}) {
const { clientId, from, to } = args;
const address = useActiveAccount()?.address;
const chainStore = useAllChainsData();

return useQuery<UserOpStats>({
queryKey: accountKeys.userOpStats(
address || "",
clientId,
from?.toISOString() || "",
to?.toISOString() || "",
"all",
),
queryFn: async () => {
const userOpStats = await getUserOpUsage({
clientId,
from,
to,
period: "all",
});

// Aggregate stats across wallet types
return userOpStats.reduce(
(acc, curr) => {
// Skip testnets from the aggregated stats
if (curr.chainId) {
const chain = chainStore.idToChain.get(Number(curr.chainId));
if (chain?.testnet) {
return acc;
}
}

acc.successful += curr.successful;
acc.failed += curr.failed;
acc.sponsoredUsd += curr.sponsoredUsd;
return acc;
},
{
date: (from || new Date()).toISOString(),
successful: 0,
failed: 0,
sponsoredUsd: 0,
},
);
},
enabled: !!clientId && !!address,
});
}

// TODO - remove this hook, fetch this on server
export function useUserOpUsagePeriod(args: {
clientId: string;
from?: Date;
to?: Date;
period: "day" | "week" | "month" | "year";
}) {
const { clientId, from, to, period } = args;
const address = useActiveAccount()?.address;

return useQuery({
queryKey: accountKeys.userOpStats(
address || "",
clientId as string,
from?.toISOString() || "",
to?.toISOString() || "",
period,
),
queryFn: async () => {
return getUserOpUsage({
clientId,
from,
to,
period,
});
},
enabled: !!clientId && !!address,
});
}

export function useUpdateAccount() {
const queryClient = useQueryClient();
const address = useActiveAccount()?.address;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
ChainMetadataWithServices,
ChainSupportedService,
} from "../../../types/chain";
import { getChains } from "../../../utils";
import { getChainsWithServices } from "../../../utils";
import { ChainlistPagination } from "../client/pagination";
import { ChainListCard } from "../server/chainlist-card";
import { ChainListRow } from "../server/chainlist-row";
Expand All @@ -35,7 +35,7 @@ const DEFAULT_PAGE_SIZE = 24;
const DEFAULT_PAGE = 1;

async function getChainsToRender(params: SearchParams) {
const chains = await getChains();
const chains = await getChainsWithServices();

// sort the chains
const sortedChains = chains.sort((a, b) => {
Expand Down
28 changes: 9 additions & 19 deletions apps/dashboard/src/app/(dashboard)/(chain)/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,19 @@ import zytronBanner from "./temp-assets/zytronBanner.png";
import zytronCTA from "./temp-assets/zytronCTA.jpg";
// END TEMPORARY

import {
getChainServices,
getChains,
getGasSponsoredChains,
} from "@/api/chain";
import { API_SERVER_URL } from "@/constants/env";
import type { ChainMetadata } from "thirdweb/chains";
import { getGasSponsoredChains } from "../../../@/api/chain";
import type {
ChainMetadataWithServices,
ChainService,
ChainServices,
} from "./types/chain";
import type { ChainMetadataWithServices, ChainServices } from "./types/chain";

export async function getChains() {
export async function getChainsWithServices() {
const [chains, chainServices] = await Promise.all([
fetch(
`${API_SERVER_URL}/v1/chains`,
// revalidate every 60 minutes
{ next: { revalidate: 60 * 60 } },
).then((res) => res.json()) as Promise<{ data: ChainMetadata[] }>,
fetch(
`${API_SERVER_URL}/v1/chains/services`,
// revalidate every 60 minutes
{ next: { revalidate: 60 * 60 } },
).then((res) => res.json()) as Promise<{
data: Record<number, Array<ChainService>>;
}>,
getChains(),
getChainServices(),
]);

if (!chains.data.length) {
Expand Down
41 changes: 22 additions & 19 deletions apps/dashboard/src/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ThemeProvider, useTheme } from "next-themes";
import { NuqsAdapter } from "nuqs/adapters/next/app";
import { useEffect, useMemo } from "react";
import { Toaster } from "sonner";
import {
Expand All @@ -20,25 +21,27 @@ const queryClient = new QueryClient();

export function AppRouterProviders(props: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
<SyncChainStores />
<ThirdwebProvider>
<SyncChainDefinitionsToConnectionManager />
<TWAutoConnect />
<PosthogIdentifier />
<ThemeProvider
attribute="class"
disableTransitionOnChange
enableSystem={false}
defaultTheme="dark"
>
<ToasterSetup />
<SanctionedAddressesChecker>
{props.children}
</SanctionedAddressesChecker>
</ThemeProvider>
</ThirdwebProvider>
</QueryClientProvider>
<NuqsAdapter>
<QueryClientProvider client={queryClient}>
<SyncChainStores />
<ThirdwebProvider>
<SyncChainDefinitionsToConnectionManager />
<TWAutoConnect />
<PosthogIdentifier />
<ThemeProvider
attribute="class"
disableTransitionOnChange
enableSystem={false}
defaultTheme="dark"
>
<ToasterSetup />
<SanctionedAddressesChecker>
{props.children}
</SanctionedAddressesChecker>
</ThemeProvider>
</ThirdwebProvider>
</QueryClientProvider>
</NuqsAdapter>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ async function OverviewPageContent(props: {
}),
// User operations usage
getUserOpUsage({
accountId: account.id,
teamId,
from: range.from,
to: range.to,
period: interval,
}),
getUserOpUsage({
accountId: account.id,
teamId,
from: range.from,
to: range.to,
period: "all",
Expand Down
Loading
Loading