Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
9 changes: 0 additions & 9 deletions apps/dashboard/src/@/actions/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,6 @@ export async function engineCloudProxy<T>(params: ProxyActionParams) {
return proxy<T>(THIRDWEB_ENGINE_CLOUD_URL, params);
}

export async function payServerProxy<T>(params: ProxyActionParams) {
return proxy<T>(
process.env.NEXT_PUBLIC_PAY_URL
? `https://${process.env.NEXT_PUBLIC_PAY_URL}`
: "https://pay.thirdweb-dev.com",
params,
);
}

export async function analyticsServerProxy<T>(params: ProxyActionParams) {
return proxy<T>(process.env.ANALYTICS_SERVICE_URL || "", params);
}
74 changes: 69 additions & 5 deletions apps/dashboard/src/@/api/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type {
InAppWalletStats,
RpcMethodStats,
TransactionStats,
UniversalBridgeStats,
UniversalBridgeWalletStats,
UserOpStats,
WalletStats,
WalletUserStats,
Expand Down Expand Up @@ -44,19 +46,22 @@ async function fetchAnalytics(
);
}
// client id DEBUG OVERRIDE
// ANALYTICS_SERVICE_URL.searchParams.delete("clientId");
// ANALYTICS_SERVICE_URL.searchParams.delete("accountId");
// ANALYTICS_SERVICE_URL.searchParams.delete("projectId");
// ANALYTICS_SERVICE_URL.searchParams.delete("teamId");
// ANALYTICS_SERVICE_URL.searchParams.append(
// "clientId",
// "...",
// "teamId",
// "team_clmb33q9w00gn1x0u2ri8z0k0",
// );
// ANALYTICS_SERVICE_URL.searchParams.append(
// "projectId",
// "prj_clyqwud5y00u1na7nzxnzlz7o",
// );

return fetch(ANALYTICS_SERVICE_URL, {
...init,
headers: {
"content-type": "application/json",
...init?.headers,
authorization: `Bearer ${token}`,
},
});
}
Expand Down Expand Up @@ -367,3 +372,62 @@ export async function getEcosystemWalletUsage(args: {

return json.data as EcosystemWalletStats[];
}

export async function getUniversalBridgeUsage(args: {
teamId: string;
projectId: string;
from?: Date;
to?: Date;
period?: "day" | "week" | "month" | "year" | "all";
}) {
const searchParams = buildSearchParams(args);
const res = await fetchAnalytics(`v2/universal?${searchParams.toString()}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

if (res?.status !== 200) {
const reason = await res?.text();
console.error(
`Failed to fetch universal bridge stats: ${res?.status} - ${res.statusText} - ${reason}`,
);
return null;
}

const json = await res.json();

return json.data as UniversalBridgeStats[];
}

export async function getUniversalBridgeWalletUsage(args: {
teamId: string;
projectId: string;
from?: Date;
to?: Date;
period?: "day" | "week" | "month" | "year" | "all";
}) {
const searchParams = buildSearchParams(args);
const res = await fetchAnalytics(
`v2/universal/wallets?${searchParams.toString()}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
},
);

if (res?.status !== 200) {
const reason = await res?.text();
console.error(
`Failed to fetch universal bridge wallet stats: ${res?.status} - ${res.statusText} - ${reason}`,
);
return null;
}

const json = await res.json();

return json.data as UniversalBridgeWalletStats[];
}
83 changes: 83 additions & 0 deletions apps/dashboard/src/@/api/universal-bridge/developer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,86 @@ export async function updateFee(props: {

return;
}

export type PaymentsResponse = {
data: Payment[];
meta: {
totalCount: number;
};
};
export type Payment = {
id: string;
blockNumber?: bigint;
transactionId: string;
clientId: string;
sender: string;
receiver: string;
developerFeeRecipient: string;
developerFeeBps: number;
transactions: Array<{
chainId: number;
transactionHash: string;
}>;
status: "PENDING" | "COMPLETED" | "FAILED" | "NOT_FOUND";
type: "buy" | "sell" | "transfer";
originAmount: bigint;
destinationAmount: bigint;
purchaseData: unknown;
originToken: {
address: string;
symbol: string;
decimals: number;
chainId: number;
};
destinationToken: {
address: string;
symbol: string;
decimals: number;
chainId: number;
};
createdAt: string;
};

export async function getPayments(props: {
clientId: string;
limit?: number;
offset?: number;
}) {
const authToken = await getAuthToken();

// Build URL with query parameters if provided
let url = `${UB_BASE_URL}/v1/developer/payments`;
const queryParams = new URLSearchParams();

if (props.limit) {
queryParams.append("limit", props.limit.toString());
}

if (props.offset) {
queryParams.append("offset", props.offset.toString());
}

// Append query params to URL if any exist
const queryString = queryParams.toString();
if (queryString) {
url = `${url}?${queryString}`;
}

const res = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
"x-client-id-override": props.clientId,
Authorization: `Bearer ${authToken}`,
},
});

if (!res.ok) {
const text = await res.text();
throw new Error(text);
}

const json = await res.json();
console.log("json", json);
return json as PaymentsResponse;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { getProject } from "@/api/projects";
import { PayAnalytics } from "components/pay/PayAnalytics/PayAnalytics";
import { redirect } from "next/navigation";
import {
ResponsiveSearchParamsProvider,
ResponsiveSuspense,
} from "responsive-rsc";
import { Spinner } from "../../../../../../../@/components/ui/Spinner/Spinner";
import { PayAnalyticsFilter } from "../../../../../../../components/pay/PayAnalytics/components/PayAnalyticsFilter";
import { getUniversalBridgeFiltersFromSearchParams } from "../../../../../../../lib/time";

export default async function Page(props: {
params: Promise<{
team_slug: string;
project_slug: string;
}>;
searchParams: {
from?: string | undefined | string[];
to?: string | undefined | string[];
interval?: string | undefined | string[];
};
}) {
const params = await props.params;
const project = await getProject(params.team_slug, params.project_slug);
Expand All @@ -15,11 +27,36 @@ export default async function Page(props: {
redirect(`/team/${params.team_slug}`);
}

const searchParams = await props.searchParams;
const { range, interval } = getUniversalBridgeFiltersFromSearchParams({
from: searchParams.from,
to: searchParams.to,
interval: searchParams.interval,
});

return (
<PayAnalytics
clientId={project.publishableKey}
projectId={project.id}
teamId={project.teamId}
/>
<ResponsiveSearchParamsProvider value={props.searchParams}>
<div>
<div className="mb-4 flex justify-end">
<PayAnalyticsFilter />
</div>
<ResponsiveSuspense
searchParamsUsed={["from", "to", "interval"]}
fallback={
<div className="flex w-full items-center justify-center py-24">
<Spinner className="size-8" />
</div>
}
>
<PayAnalytics
clientId={project.publishableKey}
projectId={project.id}
teamId={project.teamId}
range={range}
interval={interval}
/>
</ResponsiveSuspense>
</div>
</ResponsiveSearchParamsProvider>
);
}
Loading
Loading