@@ -30,12 +30,26 @@ let cachedData: Map<string, { data: ChainMetrics; timestamp: number; icmTimeRang
3030async function getTimeSeriesData (
3131 metricType : string ,
3232 chainId : string ,
33- timeRange : string ,
33+ timeRange : string ,
34+ startTimestamp ?: number ,
35+ endTimestamp ?: number ,
3436 pageSize : number = 365 ,
3537 fetchAllPages : boolean = false
3638) : Promise < TimeSeriesDataPoint [ ] > {
3739 try {
38- const { startTimestamp, endTimestamp } = getTimestampsFromTimeRange ( timeRange ) ;
40+ // Use provided timestamps if available, otherwise use timeRange
41+ let finalStartTimestamp : number ;
42+ let finalEndTimestamp : number ;
43+
44+ if ( startTimestamp !== undefined && endTimestamp !== undefined ) {
45+ finalStartTimestamp = startTimestamp ;
46+ finalEndTimestamp = endTimestamp ;
47+ } else {
48+ const timestamps = getTimestampsFromTimeRange ( timeRange ) ;
49+ finalStartTimestamp = timestamps . startTimestamp ;
50+ finalEndTimestamp = timestamps . endTimestamp ;
51+ }
52+
3953 let allResults : any [ ] = [ ] ;
4054
4155 const avalanche = new Avalanche ( {
@@ -46,8 +60,8 @@ async function getTimeSeriesData(
4660 const params : any = {
4761 chainId : chainId ,
4862 metric : metricType as any ,
49- startTimestamp,
50- endTimestamp,
63+ startTimestamp : finalStartTimestamp ,
64+ endTimestamp : finalEndTimestamp ,
5165 timeInterval : "day" ,
5266 pageSize,
5367 } ;
@@ -82,19 +96,29 @@ async function getTimeSeriesData(
8296 }
8397}
8498
85- async function getICMData ( chainId : string , timeRange : string ) : Promise < ICMDataPoint [ ] > {
99+ async function getICMData ( chainId : string , timeRange : string , startTimestamp ?: number , endTimestamp ?: number ) : Promise < ICMDataPoint [ ] > {
86100 try {
87- const getDaysFromTimeRange = ( range : string ) : number => {
88- switch ( range ) {
89- case '7d' : return 7 ;
90- case '30d' : return 30 ;
91- case '90d' : return 90 ;
92- case 'all' : return 365 ;
93- default : return 30 ;
94- }
95- } ;
101+ let days : number ;
102+
103+ if ( startTimestamp !== undefined && endTimestamp !== undefined ) {
104+ // Calculate days from timestamps
105+ const startDate = new Date ( startTimestamp * 1000 ) ;
106+ const endDate = new Date ( endTimestamp * 1000 ) ;
107+ const diffTime = Math . abs ( endDate . getTime ( ) - startDate . getTime ( ) ) ;
108+ days = Math . ceil ( diffTime / ( 1000 * 60 * 60 * 24 ) ) ;
109+ } else {
110+ const getDaysFromTimeRange = ( range : string ) : number => {
111+ switch ( range ) {
112+ case '7d' : return 7 ;
113+ case '30d' : return 30 ;
114+ case '90d' : return 90 ;
115+ case 'all' : return 365 ;
116+ default : return 30 ;
117+ }
118+ } ;
119+ days = getDaysFromTimeRange ( timeRange ) ;
120+ }
96121
97- const days = getDaysFromTimeRange ( timeRange ) ;
98122 const response = await fetch ( `https://idx6.solokhin.com/api/${ chainId } /metrics/dailyMessageVolume?days=${ days } ` , {
99123 headers : { 'Accept' : 'application/json' } ,
100124 } ) ;
@@ -108,7 +132,7 @@ async function getICMData(chainId: string, timeRange: string): Promise<ICMDataPo
108132 return [ ] ;
109133 }
110134
111- return data
135+ let filteredData = data
112136 . sort ( ( a : any , b : any ) => b . timestamp - a . timestamp )
113137 . map ( ( item : any ) => ( {
114138 timestamp : item . timestamp ,
@@ -117,6 +141,15 @@ async function getICMData(chainId: string, timeRange: string): Promise<ICMDataPo
117141 incomingCount : item . incomingCount || 0 ,
118142 outgoingCount : item . outgoingCount || 0 ,
119143 } ) ) ;
144+
145+ // Filter by timestamps if provided
146+ if ( startTimestamp !== undefined && endTimestamp !== undefined ) {
147+ filteredData = filteredData . filter ( ( item : ICMDataPoint ) => {
148+ return item . timestamp >= startTimestamp && item . timestamp <= endTimestamp ;
149+ } ) ;
150+ }
151+
152+ return filteredData ;
120153 } catch ( error ) {
121154 console . warn ( `Failed to fetch ICM data for chain ${ chainId } :` , error ) ;
122155 return [ ] ;
@@ -131,6 +164,8 @@ export async function GET(
131164 try {
132165 const { searchParams } = new URL ( request . url ) ;
133166 const timeRange = searchParams . get ( 'timeRange' ) || '30d' ;
167+ const startTimestampParam = searchParams . get ( 'startTimestamp' ) ;
168+ const endTimestampParam = searchParams . get ( 'endTimestamp' ) ;
134169 const resolvedParams = await params ;
135170 const chainId = resolvedParams . chainId ;
136171
@@ -141,7 +176,34 @@ export async function GET(
141176 ) ;
142177 }
143178
144- const cacheKey = `${ chainId } -${ timeRange } ` ;
179+ // Parse timestamps if provided
180+ const startTimestamp = startTimestampParam ? parseInt ( startTimestampParam , 10 ) : undefined ;
181+ const endTimestamp = endTimestampParam ? parseInt ( endTimestampParam , 10 ) : undefined ;
182+
183+ // Validate timestamps
184+ if ( startTimestamp !== undefined && isNaN ( startTimestamp ) ) {
185+ return NextResponse . json (
186+ { error : 'Invalid startTimestamp parameter' } ,
187+ { status : 400 }
188+ ) ;
189+ }
190+ if ( endTimestamp !== undefined && isNaN ( endTimestamp ) ) {
191+ return NextResponse . json (
192+ { error : 'Invalid endTimestamp parameter' } ,
193+ { status : 400 }
194+ ) ;
195+ }
196+ if ( startTimestamp !== undefined && endTimestamp !== undefined && startTimestamp > endTimestamp ) {
197+ return NextResponse . json (
198+ { error : 'startTimestamp must be less than or equal to endTimestamp' } ,
199+ { status : 400 }
200+ ) ;
201+ }
202+
203+ // Create cache key including timestamps if provided
204+ const cacheKey = startTimestamp !== undefined && endTimestamp !== undefined
205+ ? `${ chainId } -${ startTimestamp } -${ endTimestamp } `
206+ : `${ chainId } -${ timeRange } ` ;
145207
146208 if ( searchParams . get ( 'clearCache' ) === 'true' ) {
147209 cachedData . clear ( ) ;
@@ -150,7 +212,8 @@ export async function GET(
150212 const cached = cachedData . get ( cacheKey ) ;
151213
152214 if ( cached && Date . now ( ) - cached . timestamp < STATS_CONFIG . CACHE . LONG_DURATION ) {
153- if ( cached . icmTimeRange !== timeRange ) {
215+ // Only refetch ICM data if timeRange changed (not for timestamp-based queries)
216+ if ( startTimestamp === undefined && endTimestamp === undefined && cached . icmTimeRange !== timeRange ) {
154217 try {
155218 const newICMData = await getICMData ( chainId , timeRange ) ;
156219 cached . data . icmMessages = createICMMetric ( newICMData ) ;
@@ -199,24 +262,24 @@ export async function GET(
199262 feesPaidData ,
200263 icmData ,
201264 ] = await Promise . all ( [
202- getTimeSeriesData ( 'activeAddresses' , chainId , timeRange , pageSize , fetchAllPages ) ,
203- getTimeSeriesData ( 'activeSenders' , chainId , timeRange , pageSize , fetchAllPages ) ,
204- getTimeSeriesData ( 'cumulativeAddresses' , chainId , timeRange , pageSize , fetchAllPages ) ,
205- getTimeSeriesData ( 'cumulativeDeployers' , chainId , timeRange , pageSize , fetchAllPages ) ,
206- getTimeSeriesData ( 'txCount' , chainId , timeRange , pageSize , fetchAllPages ) ,
207- getTimeSeriesData ( 'cumulativeTxCount' , chainId , timeRange , pageSize , fetchAllPages ) ,
208- getTimeSeriesData ( 'cumulativeContracts' , chainId , timeRange , pageSize , fetchAllPages ) ,
209- getTimeSeriesData ( 'contracts' , chainId , timeRange , pageSize , fetchAllPages ) ,
210- getTimeSeriesData ( 'deployers' , chainId , timeRange , pageSize , fetchAllPages ) ,
211- getTimeSeriesData ( 'gasUsed' , chainId , timeRange , pageSize , fetchAllPages ) ,
212- getTimeSeriesData ( 'avgGps' , chainId , timeRange , pageSize , fetchAllPages ) ,
213- getTimeSeriesData ( 'maxGps' , chainId , timeRange , pageSize , fetchAllPages ) ,
214- getTimeSeriesData ( 'avgTps' , chainId , timeRange , pageSize , fetchAllPages ) ,
215- getTimeSeriesData ( 'maxTps' , chainId , timeRange , pageSize , fetchAllPages ) ,
216- getTimeSeriesData ( 'avgGasPrice' , chainId , timeRange , pageSize , fetchAllPages ) ,
217- getTimeSeriesData ( 'maxGasPrice' , chainId , timeRange , pageSize , fetchAllPages ) ,
218- getTimeSeriesData ( 'feesPaid' , chainId , timeRange , pageSize , fetchAllPages ) ,
219- getICMData ( chainId , timeRange ) ,
265+ getTimeSeriesData ( 'activeAddresses' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
266+ getTimeSeriesData ( 'activeSenders' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
267+ getTimeSeriesData ( 'cumulativeAddresses' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
268+ getTimeSeriesData ( 'cumulativeDeployers' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
269+ getTimeSeriesData ( 'txCount' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
270+ getTimeSeriesData ( 'cumulativeTxCount' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
271+ getTimeSeriesData ( 'cumulativeContracts' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
272+ getTimeSeriesData ( 'contracts' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
273+ getTimeSeriesData ( 'deployers' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
274+ getTimeSeriesData ( 'gasUsed' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
275+ getTimeSeriesData ( 'avgGps' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
276+ getTimeSeriesData ( 'maxGps' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
277+ getTimeSeriesData ( 'avgTps' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
278+ getTimeSeriesData ( 'maxTps' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
279+ getTimeSeriesData ( 'avgGasPrice' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
280+ getTimeSeriesData ( 'maxGasPrice' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
281+ getTimeSeriesData ( 'feesPaid' , chainId , timeRange , startTimestamp , endTimestamp , pageSize , fetchAllPages ) ,
282+ getICMData ( chainId , timeRange , startTimestamp , endTimestamp ) ,
220283 ] ) ;
221284
222285 const metrics : ChainMetrics = {
0 commit comments