Skip to content

Commit 451594c

Browse files
authored
Feature: Migrate Universal Bridge Analytics (#6988)
1 parent 9634e49 commit 451594c

File tree

24 files changed

+1069
-2062
lines changed

24 files changed

+1069
-2062
lines changed

apps/dashboard/src/@/actions/proxies.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
44
import {
55
NEXT_PUBLIC_ENGINE_CLOUD_URL,
6-
NEXT_PUBLIC_PAY_URL,
76
NEXT_PUBLIC_THIRDWEB_API_HOST,
87
} from "../constants/public-envs";
98
import { ANALYTICS_SERVICE_URL } from "../constants/server-envs";
@@ -88,15 +87,6 @@ export async function engineCloudProxy<T>(params: ProxyActionParams) {
8887
return proxy<T>(NEXT_PUBLIC_ENGINE_CLOUD_URL, params);
8988
}
9089

91-
export async function payServerProxy<T>(params: ProxyActionParams) {
92-
return proxy<T>(
93-
NEXT_PUBLIC_PAY_URL
94-
? `https://${NEXT_PUBLIC_PAY_URL}`
95-
: "https://pay.thirdweb-dev.com",
96-
params,
97-
);
98-
}
99-
10090
export async function analyticsServerProxy<T>(params: ProxyActionParams) {
10191
return proxy<T>(ANALYTICS_SERVICE_URL, params);
10292
}

apps/dashboard/src/@/api/analytics.ts

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import type {
66
InAppWalletStats,
77
RpcMethodStats,
88
TransactionStats,
9+
UniversalBridgeStats,
10+
UniversalBridgeWalletStats,
911
UserOpStats,
1012
WalletStats,
1113
WalletUserStats,
@@ -46,19 +48,22 @@ async function fetchAnalytics(
4648
);
4749
}
4850
// client id DEBUG OVERRIDE
49-
// analyticsServiceUrl.searchParams.delete("clientId");
50-
// analyticsServiceUrl.searchParams.delete("accountId");
51-
// analyticsServiceUrl.searchParams.append(
52-
// "clientId",
53-
// "...",
51+
// ANALYTICS_SERVICE_URL.searchParams.delete("projectId");
52+
// ANALYTICS_SERVICE_URL.searchParams.delete("teamId");
53+
// ANALYTICS_SERVICE_URL.searchParams.append(
54+
// "teamId",
55+
// "team_clmb33q9w00gn1x0u2ri8z0k0",
56+
// );
57+
// ANALYTICS_SERVICE_URL.searchParams.append(
58+
// "projectId",
59+
// "prj_clyqwud5y00u1na7nzxnzlz7o",
5460
// );
5561

5662
return fetch(analyticsServiceUrl, {
5763
...init,
5864
headers: {
5965
"content-type": "application/json",
6066
...init?.headers,
61-
authorization: `Bearer ${token}`,
6267
},
6368
});
6469
}
@@ -369,3 +374,62 @@ export async function getEcosystemWalletUsage(args: {
369374

370375
return json.data as EcosystemWalletStats[];
371376
}
377+
378+
export async function getUniversalBridgeUsage(args: {
379+
teamId: string;
380+
projectId: string;
381+
from?: Date;
382+
to?: Date;
383+
period?: "day" | "week" | "month" | "year" | "all";
384+
}) {
385+
const searchParams = buildSearchParams(args);
386+
const res = await fetchAnalytics(`v2/universal?${searchParams.toString()}`, {
387+
method: "GET",
388+
headers: {
389+
"Content-Type": "application/json",
390+
},
391+
});
392+
393+
if (res?.status !== 200) {
394+
const reason = await res?.text();
395+
console.error(
396+
`Failed to fetch universal bridge stats: ${res?.status} - ${res.statusText} - ${reason}`,
397+
);
398+
return null;
399+
}
400+
401+
const json = await res.json();
402+
403+
return json.data as UniversalBridgeStats[];
404+
}
405+
406+
export async function getUniversalBridgeWalletUsage(args: {
407+
teamId: string;
408+
projectId: string;
409+
from?: Date;
410+
to?: Date;
411+
period?: "day" | "week" | "month" | "year" | "all";
412+
}) {
413+
const searchParams = buildSearchParams(args);
414+
const res = await fetchAnalytics(
415+
`v2/universal/wallets?${searchParams.toString()}`,
416+
{
417+
method: "GET",
418+
headers: {
419+
"Content-Type": "application/json",
420+
},
421+
},
422+
);
423+
424+
if (res?.status !== 200) {
425+
const reason = await res?.text();
426+
console.error(
427+
`Failed to fetch universal bridge wallet stats: ${res?.status} - ${res.statusText} - ${reason}`,
428+
);
429+
return null;
430+
}
431+
432+
const json = await res.json();
433+
434+
return json.data as UniversalBridgeWalletStats[];
435+
}

apps/dashboard/src/@/api/universal-bridge/developer.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,85 @@ export async function updateFee(props: {
145145

146146
return;
147147
}
148+
149+
export type PaymentsResponse = {
150+
data: Payment[];
151+
meta: {
152+
totalCount: number;
153+
};
154+
};
155+
export type Payment = {
156+
id: string;
157+
blockNumber?: bigint;
158+
transactionId: string;
159+
clientId: string;
160+
sender: string;
161+
receiver: string;
162+
developerFeeRecipient: string;
163+
developerFeeBps: number;
164+
transactions: Array<{
165+
chainId: number;
166+
transactionHash: string;
167+
}>;
168+
status: "PENDING" | "COMPLETED" | "FAILED" | "NOT_FOUND";
169+
type: "buy" | "sell" | "transfer";
170+
originAmount: bigint;
171+
destinationAmount: bigint;
172+
purchaseData: unknown;
173+
originToken: {
174+
address: string;
175+
symbol: string;
176+
decimals: number;
177+
chainId: number;
178+
};
179+
destinationToken: {
180+
address: string;
181+
symbol: string;
182+
decimals: number;
183+
chainId: number;
184+
};
185+
createdAt: string;
186+
};
187+
188+
export async function getPayments(props: {
189+
clientId: string;
190+
limit?: number;
191+
offset?: number;
192+
}) {
193+
const authToken = await getAuthToken();
194+
195+
// Build URL with query parameters if provided
196+
let url = `${UB_BASE_URL}/v1/developer/payments`;
197+
const queryParams = new URLSearchParams();
198+
199+
if (props.limit) {
200+
queryParams.append("limit", props.limit.toString());
201+
}
202+
203+
if (props.offset) {
204+
queryParams.append("offset", props.offset.toString());
205+
}
206+
207+
// Append query params to URL if any exist
208+
const queryString = queryParams.toString();
209+
if (queryString) {
210+
url = `${url}?${queryString}`;
211+
}
212+
213+
const res = await fetch(url, {
214+
method: "GET",
215+
headers: {
216+
"Content-Type": "application/json",
217+
"x-client-id-override": props.clientId,
218+
Authorization: `Bearer ${authToken}`,
219+
},
220+
});
221+
222+
if (!res.ok) {
223+
const text = await res.text();
224+
throw new Error(text);
225+
}
226+
227+
const json = await res.json();
228+
return json as PaymentsResponse;
229+
}

apps/dashboard/src/@/constants/public-envs.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,5 @@ export const NEXT_PUBLIC_THIRDWEB_ENGINE_FAUCET_WALLET =
3232

3333
export const NEXT_PUBLIC_NEBULA_URL = process.env.NEXT_PUBLIC_NEBULA_URL || "";
3434

35-
export const NEXT_PUBLIC_PAY_URL = process.env.NEXT_PUBLIC_PAY_URL || "";
36-
3735
export const NEXT_PUBLIC_DEMO_ENGINE_URL =
3836
process.env.NEXT_PUBLIC_DEMO_ENGINE_URL || "";
Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import { getProject } from "@/api/projects";
22
import { PayAnalytics } from "components/pay/PayAnalytics/PayAnalytics";
33
import { redirect } from "next/navigation";
4+
import {
5+
ResponsiveSearchParamsProvider,
6+
ResponsiveSuspense,
7+
} from "responsive-rsc";
8+
import { Spinner } from "../../../../../../../@/components/ui/Spinner/Spinner";
9+
import { PayAnalyticsFilter } from "../../../../../../../components/pay/PayAnalytics/components/PayAnalyticsFilter";
10+
import { getUniversalBridgeFiltersFromSearchParams } from "../../../../../../../lib/time";
411

512
export default async function Page(props: {
613
params: Promise<{
714
team_slug: string;
815
project_slug: string;
916
}>;
17+
searchParams: {
18+
from?: string | undefined | string[];
19+
to?: string | undefined | string[];
20+
interval?: string | undefined | string[];
21+
};
1022
}) {
1123
const params = await props.params;
1224
const project = await getProject(params.team_slug, params.project_slug);
@@ -15,11 +27,36 @@ export default async function Page(props: {
1527
redirect(`/team/${params.team_slug}`);
1628
}
1729

30+
const searchParams = await props.searchParams;
31+
const { range, interval } = getUniversalBridgeFiltersFromSearchParams({
32+
from: searchParams.from,
33+
to: searchParams.to,
34+
interval: searchParams.interval,
35+
});
36+
1837
return (
19-
<PayAnalytics
20-
clientId={project.publishableKey}
21-
projectId={project.id}
22-
teamId={project.teamId}
23-
/>
38+
<ResponsiveSearchParamsProvider value={props.searchParams}>
39+
<div>
40+
<div className="mb-4 flex justify-end">
41+
<PayAnalyticsFilter />
42+
</div>
43+
<ResponsiveSuspense
44+
searchParamsUsed={["from", "to", "interval"]}
45+
fallback={
46+
<div className="flex w-full items-center justify-center py-24">
47+
<Spinner className="size-8" />
48+
</div>
49+
}
50+
>
51+
<PayAnalytics
52+
clientId={project.publishableKey}
53+
projectId={project.id}
54+
teamId={project.teamId}
55+
range={range}
56+
interval={interval}
57+
/>
58+
</ResponsiveSuspense>
59+
</div>
60+
</ResponsiveSearchParamsProvider>
2461
);
2562
}

0 commit comments

Comments
 (0)