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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ export async function isInsightSupportedForChain(
);

if (!res.ok) {
const errorText = await res.text();
console.error(
"failed to fetch chain services for chain",
chainId,
errorText,
);
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { NEXT_PUBLIC_DASHBOARD_CLIENT_ID } from "@/constants/public-envs";
import { getVercelEnv } from "@/utils/vercel";

type InsightAggregationEntry = {
event_signature: string;
time: string;
topic_0: string;
day: string;
count: number;
};

Expand All @@ -26,12 +26,18 @@ export async function getContractEventBreakdown(params: {
startDate?: Date;
endDate?: Date;
}): Promise<EventBreakdownEntry[]> {
const daysDifference =
params.startDate && params.endDate
? Math.ceil(
(params.endDate.getTime() - params.startDate.getTime()) /
(1000 * 60 * 60 * 24),
)
: 30;
Comment on lines +29 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Clamp daysDifference to avoid negative/zero limit; prevent bad queries

If endDate < startDate (or same day), limit can go ≤ 0. Clamp to ≥1.

Apply:

-  const daysDifference =
-    params.startDate && params.endDate
-      ? Math.ceil(
-          (params.endDate.getTime() - params.startDate.getTime()) /
-            (1000 * 60 * 60 * 24),
-        )
-      : 30;
+  const daysDifference = Math.max(
+    1,
+    params.startDate && params.endDate
+      ? Math.ceil(
+          (params.endDate.getTime() - params.startDate.getTime()) /
+            (1000 * 60 * 60 * 24),
+        )
+      : 30,
+  );

Also applies to: 38-41

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/utils/contract-event-breakdown.ts
around lines 29-35 (and similarly 38-41), the computed daysDifference can be 0
or negative when endDate <= startDate which yields an invalid limit; clamp the
calculated daysDifference to a minimum of 1 before using it (e.g., wrap the
Math.ceil expression with Math.max(1, ...)) and apply the same clamp to the
other occurrence on lines 38-41 so limit is always ≥1.

const queryParams = [
`chain=${params.chainId}`,
"group_by=time",
"group_by=topic_0 as event_signature",
"aggregate=toStartOfDay(toDate(block_timestamp)) as time",
"aggregate=count(*) as count",
"group_by=day",
"group_by=topic_0",
`limit=${daysDifference * 10}`, // at most 10 topics per day
params.startDate
? `filter_block_timestamp_gte=${getUnixTime(params.startDate)}`
: "",
Expand All @@ -42,14 +48,13 @@ export async function getContractEventBreakdown(params: {
.filter(Boolean)
.join("&");

const res = await fetch(
`https://insight.${thirdwebDomain}.com/v1/events/${params.contractAddress}?${queryParams}`,
{
headers: {
"x-client-id": NEXT_PUBLIC_DASHBOARD_CLIENT_ID,
},
const url = `https://insight.${thirdwebDomain}.com/v1/events/${params.contractAddress}?${queryParams}`;

const res = await fetch(url, {
headers: {
"x-client-id": NEXT_PUBLIC_DASHBOARD_CLIENT_ID,
},
);
});

if (!res.ok) {
throw new Error("Failed to fetch analytics data");
Expand All @@ -63,17 +68,16 @@ export async function getContractEventBreakdown(params: {
if (
typeof value === "object" &&
value !== null &&
"time" in value &&
"day" in value &&
"count" in value &&
"event_signature" in value &&
typeof value.event_signature === "string" &&
typeof value.time === "string" &&
typeof value.count === "number"
"topic_0" in value &&
typeof value.topic_0 === "string" &&
typeof value.day === "string"
) {
collectedAggregations.push({
count: value.count,
event_signature: value.event_signature,
time: value.time,
count: Number(value.count),
topic_0: value.topic_0,
day: value.day,
});
}
}
Expand All @@ -84,15 +88,15 @@ export async function getContractEventBreakdown(params: {
> = new Map();

for (const value of collectedAggregations) {
const mapKey = value.time;
const mapKey = value.day;
let valueForDay = dayToFunctionBreakdownMap.get(mapKey);
if (!valueForDay) {
valueForDay = {};
dayToFunctionBreakdownMap.set(mapKey, valueForDay);
}

valueForDay[value.event_signature] =
(valueForDay[value.event_signature] || 0) + value.count;
valueForDay[value.topic_0] =
(valueForDay[value.topic_0] || 0) + value.count;
}

const values: EventBreakdownEntry[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ export async function getContractEventAnalytics(params: {
startDate?: Date;
endDate?: Date;
}): Promise<AnalyticsEntry[]> {
const daysDifference =
params.startDate && params.endDate
? Math.ceil(
(params.endDate.getTime() - params.startDate.getTime()) /
(1000 * 60 * 60 * 24),
)
: 30;
const queryParams = [
`chain=${params.chainId}`,
"group_by=time",
"aggregate=toStartOfDay(toDate(block_timestamp)) as time",
"aggregate=count(block_timestamp) as count",
"group_by=day",
`limit=${daysDifference}`,
params.startDate
? `filter_block_timestamp_gte=${getUnixTime(params.startDate)}`
: "",
Expand All @@ -45,17 +51,17 @@ export async function getContractEventAnalytics(params: {
.filter(Boolean)
.join("&");

const res = await fetch(
`https://insight.${thirdwebDomain}.com/v1/events/${params.contractAddress}?${queryParams}`,
{
headers: {
"x-client-id": NEXT_PUBLIC_DASHBOARD_CLIENT_ID,
},
const url = `https://insight.${thirdwebDomain}.com/v1/events/${params.contractAddress}?${queryParams}`;

const res = await fetch(url, {
headers: {
"x-client-id": NEXT_PUBLIC_DASHBOARD_CLIENT_ID,
},
);
});

if (!res.ok) {
throw new Error("Failed to fetch analytics data");
const errorText = await res.text();
throw new Error(`Failed to fetch analytics data: ${errorText}`);
}

const json = (await res.json()) as InsightResponse;
Expand All @@ -67,14 +73,13 @@ export async function getContractEventAnalytics(params: {
if (
typeof value === "object" &&
value !== null &&
"time" in value &&
"day" in value &&
"count" in value &&
typeof value.time === "string" &&
typeof value.count === "number"
typeof value.day === "string"
) {
values.push({
count: value.count,
time: new Date(value.time),
count: Number(value.count),
time: new Date(value.day),
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type InsightResponse = {
aggregations: [
{
0: {
total: number;
count: number;
};
},
];
Expand All @@ -19,10 +19,9 @@ export async function getTotalContractEvents(params: {
contractAddress: string;
chainId: number;
}): Promise<{ count: number }> {
const queryParams = [
`chain=${params.chainId}`,
"aggregate=count(block_number) as total",
].join("&");
const queryParams = [`chain=${params.chainId}`, "aggregate=count()"].join(
"&",
);

const res = await fetch(
`https://insight.${thirdwebDomain}.com/v1/events/${params.contractAddress}?${queryParams}`,
Expand All @@ -40,6 +39,6 @@ export async function getTotalContractEvents(params: {
const json = (await res.json()) as InsightResponse;

return {
count: json.aggregations[0][0].total,
count: json.aggregations[0][0].count,
};
}
Loading