use aide::axum::{ApiRouter, routing::get_with};
use axum::{
extract::{Path, State},
http::{HeaderMap, Uri},
response::IntoResponse,
};
use brk_oracle::{HistogramEmaCompact, HistogramRaw};
use brk_types::{Day1, Dollars, Version};
use crate::{
AppState,
extended::TransformResponseExtended,
params::{Empty, HeightOrDate, HeightOrDateParam},
};
pub trait OracleRoutes {
fn add_oracle_routes(self) -> Self;
}
impl OracleRoutes for ApiRouter<AppState> {
fn add_oracle_routes(self) -> Self {
self.api_route(
"/api/oracle/price",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| q.live_price())
.await
},
|op| {
op.id("get_oracle_price")
.oracle_tag()
.summary("Live BTC/USD price")
.description(
"Current BTC/USD price in dollars. Same value as \
`/api/mempool/price`. Confirmed per-height history is available at \
`/api/vecs/height-to-price`.",
)
.json_response::<Dollars>()
.not_modified()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/payments/live",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| {
q.live_payment_histogram()
})
.await
},
|op| {
op.id("get_oracle_histogram_payments_live")
.oracle_tag()
.summary("Live payment output histogram")
.description(
"Live smoothed histogram of oracle-eligible payment outputs, binned \
by output value on the oracle log scale. It combines the committed \
oracle window with the forming mempool block. A flat array of \
log-scale bins.",
)
.json_response::<HistogramEmaCompact>()
.not_modified()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/payments/{point}",
get_with(
async |uri: Uri,
headers: HeaderMap,
Path(path): Path<HeightOrDateParam>,
_: Empty,
State(state): State<AppState>| {
let version = Version::new(brk_oracle::VERSION);
match path.resolve() {
Ok(HeightOrDate::Date(date)) => {
let strategy = state.date_strategy(version, date);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_payment_histogram_day(Day1::try_from(date)?)
})
.await
}
Ok(HeightOrDate::Height(height)) => {
let strategy = state.height_strategy(version, height);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_payment_histogram(usize::from(height))
})
.await
}
Err(e) => e.into_response(),
}
},
|op| {
op.id("get_oracle_histogram_payments")
.oracle_tag()
.summary("Payment output histogram at height or day")
.description(
"Smoothed histogram of oracle-eligible payment outputs for a \
confirmed point. A block height (`840000`) gives that block's oracle \
payment histogram; a calendar date (`YYYY-MM-DD`) gives the average \
of that day's per-block payment histograms. A flat array of log-scale \
bins.",
)
.json_response::<HistogramEmaCompact>()
.not_modified()
.bad_request()
.not_found()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/outputs/live",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| {
q.live_output_histogram()
})
.await
},
|op| {
op.id("get_oracle_histogram_outputs_live")
.oracle_tag()
.summary("Live output value histogram")
.description(
"Live unfiltered output value histogram for the forming mempool \
block. Every live output is binned by value on the oracle log scale; \
no oracle payment filters are applied. A flat array of log-scale \
bins, all zero when no mempool is configured.",
)
.json_response::<HistogramRaw>()
.not_modified()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/outputs/{point}",
get_with(
async |uri: Uri,
headers: HeaderMap,
Path(path): Path<HeightOrDateParam>,
_: Empty,
State(state): State<AppState>| {
let version = Version::new(brk_oracle::VERSION);
match path.resolve() {
Ok(HeightOrDate::Date(date)) => {
let strategy = state.date_strategy(version, date);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_output_histogram_day(Day1::try_from(date)?)
})
.await
}
Ok(HeightOrDate::Height(height)) => {
let strategy = state.height_strategy(version, height);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_output_histogram(usize::from(height))
})
.await
}
Err(e) => e.into_response(),
}
},
|op| {
op.id("get_oracle_histogram_outputs")
.oracle_tag()
.summary("Output value histogram at height or day")
.description(
"Unfiltered output value histogram for a confirmed point. A block \
height (`840000`) gives every output in that block, coinbase \
included, binned by value on the oracle log scale; a calendar date \
(`YYYY-MM-DD`) sums every block that day. A flat array of log-scale \
bins.",
)
.json_response::<HistogramRaw>()
.not_modified()
.bad_request()
.not_found()
.server_error()
},
),
)
}
}