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
10 changes: 0 additions & 10 deletions apps/dashboard/src/@/actions/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { getAuthToken } from "../../app/(app)/api/lib/getAuthToken";
import {
NEXT_PUBLIC_ENGINE_CLOUD_URL,
NEXT_PUBLIC_PAY_URL,
NEXT_PUBLIC_THIRDWEB_API_HOST,
} from "../constants/public-envs";
import { ANALYTICS_SERVICE_URL } from "../constants/server-envs";
Expand Down Expand Up @@ -88,15 +87,6 @@ export async function engineCloudProxy<T>(params: ProxyActionParams) {
return proxy<T>(NEXT_PUBLIC_ENGINE_CLOUD_URL, params);
}

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

export async function analyticsServerProxy<T>(params: ProxyActionParams) {
return proxy<T>(ANALYTICS_SERVICE_URL, params);
}
76 changes: 70 additions & 6 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 @@ -46,19 +48,22 @@ async function fetchAnalytics(
);
}
// client id DEBUG OVERRIDE
// analyticsServiceUrl.searchParams.delete("clientId");
// analyticsServiceUrl.searchParams.delete("accountId");
// analyticsServiceUrl.searchParams.append(
// "clientId",
// "...",
// ANALYTICS_SERVICE_URL.searchParams.delete("projectId");
// ANALYTICS_SERVICE_URL.searchParams.delete("teamId");
// ANALYTICS_SERVICE_URL.searchParams.append(
// "teamId",
// "team_clmb33q9w00gn1x0u2ri8z0k0",
// );
// ANALYTICS_SERVICE_URL.searchParams.append(
// "projectId",
// "prj_clyqwud5y00u1na7nzxnzlz7o",
// );

return fetch(analyticsServiceUrl, {
...init,
headers: {
"content-type": "application/json",
...init?.headers,
authorization: `Bearer ${token}`,
},
});
}
Expand Down Expand Up @@ -369,3 +374,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[];
}
82 changes: 82 additions & 0 deletions apps/dashboard/src/@/api/universal-bridge/developer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,85 @@ 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();
return json as PaymentsResponse;
}
2 changes: 0 additions & 2 deletions apps/dashboard/src/@/constants/public-envs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,5 @@ export const NEXT_PUBLIC_THIRDWEB_ENGINE_FAUCET_WALLET =

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

export const NEXT_PUBLIC_PAY_URL = process.env.NEXT_PUBLIC_PAY_URL || "";

export const NEXT_PUBLIC_DEMO_ENGINE_URL =
process.env.NEXT_PUBLIC_DEMO_ENGINE_URL || "";
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