@@ -28,6 +28,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
2828use std:: { collections:: HashMap , net:: SocketAddr } ;
2929use sui_pg_db:: DbArgs ;
3030use tokio:: net:: TcpListener ;
31+ use tokio:: sync:: OnceCell ;
3132use tower_http:: cors:: { AllowMethods , Any , CorsLayer } ;
3233use url:: Url ;
3334
@@ -106,6 +107,8 @@ pub const DEPOSITED_ASSETS_PATH: &str = "/deposited_assets/:balance_manager_ids"
106107pub struct AppState {
107108 reader : Reader ,
108109 metrics : Arc < RpcMetrics > ,
110+ rpc_url : Url ,
111+ sui_client : Arc < OnceCell < sui_sdk:: SuiClient > > ,
109112 deepbook_package_id : String ,
110113 deep_token_package_id : String ,
111114 deep_treasury_id : String ,
@@ -116,6 +119,7 @@ impl AppState {
116119 database_url : Url ,
117120 args : DbArgs ,
118121 registry : & Registry ,
122+ rpc_url : Url ,
119123 deepbook_package_id : String ,
120124 deep_token_package_id : String ,
121125 deep_treasury_id : String ,
@@ -125,11 +129,27 @@ impl AppState {
125129 Ok ( Self {
126130 reader,
127131 metrics,
132+ rpc_url,
133+ sui_client : Arc :: new ( OnceCell :: new ( ) ) ,
128134 deepbook_package_id,
129135 deep_token_package_id,
130136 deep_treasury_id,
131137 } )
132138 }
139+
140+ /// Returns a reference to the shared SuiClient instance.
141+ /// Lazily initializes the client on first access and caches it for subsequent calls
142+ pub async fn sui_client ( & self ) -> Result < & sui_sdk:: SuiClient , DeepBookError > {
143+ self . sui_client
144+ . get_or_try_init ( || async {
145+ SuiClientBuilder :: default ( )
146+ . build ( self . rpc_url . as_str ( ) )
147+ . await
148+ } )
149+ . await
150+ . map_err ( DeepBookError :: from)
151+ }
152+
133153 pub ( crate ) fn metrics ( & self ) -> & RpcMetrics {
134154 & self . metrics
135155 }
@@ -178,6 +198,7 @@ pub async fn run_server(
178198 database_url,
179199 db_arg,
180200 metrics. registry ( ) ,
201+ rpc_url,
181202 deepbook_package_id,
182203 deep_token_package_id,
183204 deep_treasury_id,
@@ -192,15 +213,15 @@ pub async fn run_server(
192213 } ) ;
193214
194215 let listener = TcpListener :: bind ( socket_address) . await ?;
195- axum:: serve ( listener, make_router ( Arc :: new ( state) , rpc_url ) )
216+ axum:: serve ( listener, make_router ( Arc :: new ( state) ) )
196217 . with_graceful_shutdown ( async move {
197218 cancellation_token. cancelled ( ) . await ;
198219 } )
199220 . await ?;
200221
201222 Ok ( ( ) )
202223}
203- pub ( crate ) fn make_router ( state : Arc < AppState > , rpc_url : Url ) -> Router {
224+ pub ( crate ) fn make_router ( state : Arc < AppState > ) -> Router {
204225 let cors = CorsLayer :: new ( )
205226 . allow_methods ( AllowMethods :: list ( vec ! [ Method :: GET , Method :: OPTIONS ] ) )
206227 . allow_headers ( Any )
@@ -271,7 +292,7 @@ pub(crate) fn make_router(state: Arc<AppState>, rpc_url: Url) -> Router {
271292 . route ( DEEP_SUPPLY_PATH , get ( deep_supply) )
272293 . route ( SUMMARY_PATH , get ( summary) )
273294 . route ( STATUS_PATH , get ( status) )
274- . with_state ( ( state. clone ( ) , rpc_url ) ) ;
295+ . with_state ( state. clone ( ) ) ;
275296
276297 db_routes
277298 . merge ( rpc_routes)
@@ -286,13 +307,13 @@ async fn health_check() -> StatusCode {
286307/// Get indexer status including checkpoint lag
287308async fn status (
288309 Query ( params) : Query < StatusQueryParams > ,
289- State ( ( state, rpc_url ) ) : State < ( Arc < AppState > , Url ) > ,
310+ State ( state) : State < Arc < AppState > > ,
290311) -> Result < Json < serde_json:: Value > , DeepBookError > {
291312 // Get watermarks from the database
292313 let watermarks = state. reader . get_watermarks ( ) . await ?;
293314
294315 // Get the latest checkpoint from Sui RPC
295- let sui_client = SuiClientBuilder :: default ( ) . build ( rpc_url . as_str ( ) ) . await ?;
316+ let sui_client = state . sui_client ( ) . await ?;
296317 let latest_checkpoint = sui_client
297318 . read_api ( )
298319 . get_latest_checkpoint_sequence_number ( )
@@ -680,7 +701,7 @@ async fn fetch_historical_volume(
680701
681702#[ allow( clippy:: get_first) ]
682703async fn summary (
683- State ( ( state, rpc_url ) ) : State < ( Arc < AppState > , Url ) > ,
704+ State ( state) : State < Arc < AppState > > ,
684705) -> Result < Json < Vec < HashMap < String , Value > > > , DeepBookError > {
685706 // Fetch pools metadata first since it's required for other functions
686707 let pools = state. reader . get_pools ( ) . await ?;
@@ -722,7 +743,7 @@ async fn summary(
722743 orderbook (
723744 Path ( pool_name_clone) ,
724745 Query ( HashMap :: from ( [ ( "level" . to_string ( ) , "1" . to_string ( ) ) ] ) ) ,
725- State ( ( state. clone ( ) , rpc_url . clone ( ) ) ) ,
746+ State ( state. clone ( ) ) ,
726747 )
727748 } )
728749 . collect ( ) ;
@@ -1287,7 +1308,7 @@ pub async fn assets(
12871308async fn orderbook (
12881309 Path ( pool_name) : Path < String > ,
12891310 Query ( params) : Query < HashMap < String , String > > ,
1290- State ( ( state, rpc_url ) ) : State < ( Arc < AppState > , Url ) > ,
1311+ State ( state) : State < Arc < AppState > > ,
12911312) -> Result < Json < HashMap < String , Value > > , DeepBookError > {
12921313 let depth = params
12931314 . get ( "depth" )
@@ -1341,7 +1362,7 @@ async fn orderbook(
13411362
13421363 let pool_address = ObjectID :: from_hex_literal ( & pool_id) ?;
13431364
1344- let sui_client = SuiClientBuilder :: default ( ) . build ( rpc_url . as_str ( ) ) . await ?;
1365+ let sui_client = state . sui_client ( ) . await ?;
13451366 let mut ptb = ProgrammableTransactionBuilder :: new ( ) ;
13461367
13471368 let pool_object: SuiObjectResponse = sui_client
@@ -1497,10 +1518,8 @@ async fn orderbook(
14971518}
14981519
14991520/// DEEP total supply
1500- async fn deep_supply (
1501- State ( ( state, rpc_url) ) : State < ( Arc < AppState > , Url ) > ,
1502- ) -> Result < Json < u64 > , DeepBookError > {
1503- let sui_client = SuiClientBuilder :: default ( ) . build ( rpc_url. as_str ( ) ) . await ?;
1521+ async fn deep_supply ( State ( state) : State < Arc < AppState > > ) -> Result < Json < u64 > , DeepBookError > {
1522+ let sui_client = state. sui_client ( ) . await ?;
15041523 let mut ptb = ProgrammableTransactionBuilder :: new ( ) ;
15051524
15061525 let deep_treasury_object_id = ObjectID :: from_hex_literal ( & state. deep_treasury_id ) ?;
0 commit comments