kabu_rpc_handler/handler/
pools.rs1use crate::dto::pagination::Pagination;
2use crate::dto::pool::{MarketStats, Pool, PoolClass, PoolDetailsResponse, PoolProtocol, PoolResponse};
3use crate::dto::quote::{Filter, QuoteRequest, QuoteResponse};
4use alloy_primitives::Address;
5use axum::extract::{Path, Query, State};
6use axum::http::StatusCode;
7use axum::Json;
8use kabu_evm_utils::error_handler::internal_error;
9use kabu_rpc_state::AppState;
10use kabu_types_entities::{PoolId, PoolWrapper};
11use revm::{DatabaseCommit, DatabaseRef};
12use std::str::FromStr;
13
14#[utoipa::path(
18 get,
19 path = "/pools",
20 tag = "market",
21 tags = [],
22 params(
23 Pagination, Filter
24 ),
25 responses(
26 (status = 200, description = "All available pools", body = PoolResponse),
27 )
28)]
29pub async fn pools<DB: DatabaseRef + DatabaseCommit + Send + Sync + Clone + 'static>(
30 State(app_state): State<AppState<DB>>,
31 pagination: Query<Pagination>,
32 filter: Query<Filter>,
33) -> Result<Json<PoolResponse>, (StatusCode, String)> {
34 let pools: Vec<(Address, PoolWrapper)> = app_state
35 .bc
36 .market()
37 .read()
38 .await
39 .pools()
40 .iter()
41 .filter(|(_, pool)| match &filter.protocol {
42 None => true,
43 Some(protocol) => pool.pool.get_protocol() == protocol.into(),
44 })
45 .skip(pagination.start())
46 .take(pagination.limit)
47 .map(|(address, pool)| (address.address_or_zero(), pool.clone()))
48 .collect();
49
50 let mut ret = vec![];
51 for (pool_address, pool) in pools {
52 ret.push(Pool {
53 address: pool_address,
54 fee: pool.pool.get_fee(),
55 tokens: pool.pool.get_tokens(),
56 protocol: PoolProtocol::from(pool.pool.get_protocol()),
57 pool_class: PoolClass::from(pool.get_class()),
58 });
59 }
60 let total_pools = app_state
61 .bc
62 .market()
63 .read()
64 .await
65 .pools()
66 .iter()
67 .filter(|(_, pool)| match &filter.protocol {
68 None => true,
69 Some(protocol) => pool.pool.get_protocol() == protocol.into(),
70 })
71 .count();
72
73 Ok(Json(PoolResponse { pools: ret, total: total_pools }))
74}
75
76#[utoipa::path(
80 get,
81 path = "/pools/{address}",
82 tag = "market",
83 tags = [],
84 params(
85 ("address" = String, Path, description = "Address of the pool"),
86 ),
87 responses(
88 (status = 200, description = "Pool detail response", body = PoolDetailsResponse),
89 )
90)]
91pub async fn pool<DB: DatabaseRef + DatabaseCommit + Send + Sync + Clone + 'static>(
92 State(app_state): State<AppState<DB>>,
93 Path(address): Path<String>,
94) -> Result<Json<PoolDetailsResponse>, (StatusCode, String)> {
95 let address = Address::from_str(&address).map_err(internal_error)?;
96
97 match app_state.bc.market().read().await.pools().get(&PoolId::Address(address)) {
98 None => Err((StatusCode::NOT_FOUND, "Pool not found".to_string())),
99 Some(pool) => Ok(Json(PoolDetailsResponse {
100 address: pool.get_address().address_or_zero(),
101 pool_class: PoolClass::from(pool.get_class()),
102 protocol: PoolProtocol::from(pool.get_protocol()),
103 fee: pool.get_fee(),
104 tokens: pool.get_tokens(),
105 })),
106 }
107}
108
109#[utoipa::path(
113 get,
114 path = "/stats",
115 tag = "market",
116 tags = [],
117 params(
118 Pagination, Filter
119 ),
120 responses(
121 (status = 200, description = "Market stats", body = MarketStats),
122 )
123)]
124pub async fn market_stats<DB: DatabaseRef + DatabaseCommit + Send + Sync + Clone + 'static>(
125 State(app_state): State<AppState<DB>>,
126) -> Result<Json<MarketStats>, (StatusCode, String)> {
127 let total_pools = app_state.bc.market().read().await.pools().len();
128
129 Ok(Json(MarketStats { total_pools }))
130}
131
132#[utoipa::path(
136 post,
137 path = "/pools/{address}/quote",
138 tag = "market",
139 tags = [],
140 params(
141 ("address" = String, Path, description = "Address of the pool"),
142 ),
143 request_body = QuoteRequest,
144 responses(
145 (status = 200, description = "Market stats", body = QuoteResponse),
146 )
147)]
148pub async fn pool_quote<DB: DatabaseRef<Error = kabu_evm_db::KabuDBError> + DatabaseCommit + Send + Sync + Clone + 'static>(
149 State(app_state): State<AppState<DB>>,
150 Path(address): Path<String>,
151 Json(_quote_request): Json<QuoteRequest>,
152) -> Result<Json<QuoteResponse>, (StatusCode, String)> {
153 let address = Address::from_str(&address).map_err(internal_error)?;
154 match app_state.bc.market().read().await.pools().get(&PoolId::Address(address)) {
155 None => Err((StatusCode::NOT_FOUND, "Pool not found".to_string())),
156 Some(_pool) => Err((StatusCode::NOT_FOUND, "Not_implemted".to_string())),
157 }
171}