Skip to content

Commit 610be7d

Browse files
committed
feat: added new endpoint GET /historical_fees?start_date=&end_date=&interval=
Signed-off-by: kevkevinpal <oapallikunnel@gmail.com>
1 parent 6384f11 commit 610be7d

2 files changed

Lines changed: 133 additions & 0 deletions

File tree

app/src/main/kotlin/xyz/block/augurref/api/HistoricalFeeEndpoint.kt

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,95 @@ fun Route.configureHistoricalFeesEndpoint(mempoolCollector: MempoolCollector) {
7676
call.respond(response)
7777
}
7878
}
79+
80+
get("/historical_fees") {
81+
logger.info("Received request for historical fee estimates")
82+
83+
// Extract params from query start_date, end_date, interval (seconds)
84+
val startDateParam = call.request.queryParameters["start_date"]
85+
val endDateParam = call.request.queryParameters["end_date"]
86+
val intervalParam = call.request.queryParameters["interval"]
87+
val interval: Int = intervalParam?.toIntOrNull() ?: 3600
88+
89+
if (startDateParam == null) {
90+
call.respondText(
91+
"start_date parameter is required",
92+
status = HttpStatusCode.BadRequest,
93+
contentType = ContentType.Text.Plain,
94+
)
95+
return@get
96+
}
97+
98+
if (endDateParam == null) {
99+
call.respondText(
100+
"end_date parameter is required",
101+
status = HttpStatusCode.BadRequest,
102+
contentType = ContentType.Text.Plain,
103+
)
104+
return@get
105+
}
106+
107+
// Validate and parse the date
108+
val startDate = try {
109+
startDateParam?.let { LocalDateTime.parse(it) }
110+
} catch (e: DateTimeParseException) {
111+
logger.warn("Invalid date format: $startDateParam")
112+
call.respondText(
113+
"Invalid date format. Use YYYY-MM-DDTHH:MM:SS",
114+
status = HttpStatusCode.BadRequest,
115+
contentType = ContentType.Text.Plain,
116+
)
117+
return@get
118+
}
119+
val endDate = try {
120+
endDateParam?.let { LocalDateTime.parse(it) }
121+
} catch (e: DateTimeParseException) {
122+
logger.warn("Invalid date format: $endDateParam")
123+
call.respondText(
124+
"Invalid date format. Use YYYY-MM-DDTHH:MM:SS",
125+
status = HttpStatusCode.BadRequest,
126+
contentType = ContentType.Text.Plain,
127+
)
128+
return@get
129+
}
130+
131+
// Fetch historical fee estimate based on date
132+
val feeEstimate = if (startDate != null && endDate != null && interval != null) {
133+
logger.info(
134+
"Fetching historical fee estimate for start_date: $startDate to " +
135+
"end_date: $endDate for intervals: $interval seconds",
136+
)
137+
mempoolCollector.getFeeEstimateForDateRange(startDate, endDate, interval)
138+
} else {
139+
logger.warn("internal error")
140+
call.respondText(
141+
"internal error",
142+
status = HttpStatusCode.InternalServerError,
143+
contentType = ContentType.Text.Plain,
144+
)
145+
return@get
146+
}
147+
148+
if (feeEstimate == null) {
149+
logger.warn(
150+
"No historical fee estimates available for start_date $startDate to " +
151+
"end_date: $endDate for interval: $interval seconds",
152+
)
153+
call.respondText(
154+
"No historical fee estimates available for start_date $startDate to " +
155+
"end_date: $endDate for interval: $interval seconds",
156+
status = HttpStatusCode.ServiceUnavailable,
157+
contentType = ContentType.Text.Plain,
158+
)
159+
} else {
160+
var mutableResponse = mutableListOf<FeeEstimateResponse>()
161+
logger.info("Transforming historical fee estimates for response")
162+
for (estimate in feeEstimate) {
163+
val response = transformFeeEstimate(estimate)
164+
mutableResponse.add(response)
165+
}
166+
logger.debug("Returning historical fee estimates")
167+
call.respond(mutableResponse)
168+
}
169+
}
79170
}

app/src/main/kotlin/xyz/block/augurref/service/MempoolCollector.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,48 @@ class MempoolCollector(
7272
return latestFeeEstimate.get()
7373
}
7474

75+
fun getFeeEstimateForDateRange(
76+
start_date: LocalDateTime,
77+
end_date: LocalDateTime,
78+
interval: Int,
79+
): List<FeeEstimate>? {
80+
// Ensure start_date is not after end_date
81+
if (start_date.isAfter(end_date)) {
82+
logger.warn("Start date is after end date")
83+
return null
84+
}
85+
86+
// Initialize result list to store fee estimates
87+
val estimates = mutableListOf<FeeEstimate>()
88+
var currentDate = start_date
89+
90+
// Iterate through the date range with the given interval
91+
while (!currentDate.isAfter(end_date)) {
92+
logger.debug("Processing fee estimate for $currentDate")
93+
val feeEstimate = getFeeEstimateForDate(currentDate)
94+
95+
// If fee estimate is non-null and has estimates, merge them
96+
if (feeEstimate != null && feeEstimate.estimates.isNotEmpty()) {
97+
// estimates.putAll(feeEstimate.estimates as Map<Int, BlockTarget>)
98+
estimates.add(feeEstimate)
99+
} else {
100+
logger.debug("No valid fee estimate for $currentDate")
101+
}
102+
103+
// Increment currentDate by interval (in minutes)
104+
currentDate = currentDate.plusSeconds(interval.toLong())
105+
}
106+
107+
// Return null if no estimates were collected
108+
if (estimates.isEmpty()) {
109+
logger.warn("No fee estimates collected for the date range")
110+
return null
111+
}
112+
113+
// Return a FeeEstimate with the aggregated estimates
114+
return estimates
115+
}
116+
75117
/**
76118
* Get the fee estimate for specific date
77119
*/

0 commit comments

Comments
 (0)