@@ -29,6 +29,7 @@ use std::{collections::HashMap, net::SocketAddr};
2929use sui_pg_db:: DbArgs ;
3030use tokio:: net:: TcpListener ;
3131use tokio:: sync:: oneshot;
32+ use tokio:: sync:: OnceCell ;
3233use tower_http:: cors:: { AllowMethods , Any , CorsLayer } ;
3334use url:: Url ;
3435
@@ -107,6 +108,8 @@ pub const DEPOSITED_ASSETS_PATH: &str = "/deposited_assets/:balance_manager_ids"
107108pub struct AppState {
108109 reader : Reader ,
109110 metrics : Arc < RpcMetrics > ,
111+ rpc_url : Url ,
112+ sui_client : Arc < OnceCell < sui_sdk:: SuiClient > > ,
110113 deepbook_package_id : String ,
111114 deep_token_package_id : String ,
112115 deep_treasury_id : String ,
@@ -117,6 +120,7 @@ impl AppState {
117120 database_url : Url ,
118121 args : DbArgs ,
119122 registry : & Registry ,
123+ rpc_url : Url ,
120124 deepbook_package_id : String ,
121125 deep_token_package_id : String ,
122126 deep_treasury_id : String ,
@@ -126,11 +130,27 @@ impl AppState {
126130 Ok ( Self {
127131 reader,
128132 metrics,
133+ rpc_url,
134+ sui_client : Arc :: new ( OnceCell :: new ( ) ) ,
129135 deepbook_package_id,
130136 deep_token_package_id,
131137 deep_treasury_id,
132138 } )
133139 }
140+
141+ /// Returns a reference to the shared SuiClient instance.
142+ /// Lazily initializes the client on first access and caches it for subsequent calls
143+ pub async fn sui_client ( & self ) -> Result < & sui_sdk:: SuiClient , DeepBookError > {
144+ self . sui_client
145+ . get_or_try_init ( || async {
146+ SuiClientBuilder :: default ( )
147+ . build ( self . rpc_url . as_str ( ) )
148+ . await
149+ } )
150+ . await
151+ . map_err ( DeepBookError :: from)
152+ }
153+
134154 pub ( crate ) fn metrics ( & self ) -> & RpcMetrics {
135155 & self . metrics
136156 }
@@ -176,6 +196,7 @@ pub async fn run_server(
176196 database_url. clone ( ) ,
177197 db_arg. clone ( ) ,
178198 metrics. registry ( ) ,
199+ rpc_url. clone ( ) ,
179200 deepbook_package_id,
180201 deep_token_package_id,
181202 deep_treasury_id,
@@ -221,7 +242,7 @@ pub async fn run_server(
221242 let _ = stx. send ( ( ) ) ;
222243 } )
223244 . spawn ( async move {
224- axum:: serve ( listener, make_router ( Arc :: new ( state) , rpc_url ) )
245+ axum:: serve ( listener, make_router ( Arc :: new ( state) ) )
225246 . with_graceful_shutdown ( async move {
226247 let _ = srx. await ;
227248 } )
@@ -234,7 +255,7 @@ pub async fn run_server(
234255
235256 Ok ( ( ) )
236257}
237- pub ( crate ) fn make_router ( state : Arc < AppState > , rpc_url : Url ) -> Router {
258+ pub ( crate ) fn make_router ( state : Arc < AppState > ) -> Router {
238259 let cors = CorsLayer :: new ( )
239260 . allow_methods ( AllowMethods :: list ( vec ! [ Method :: GET , Method :: OPTIONS ] ) )
240261 . allow_headers ( Any )
@@ -305,7 +326,7 @@ pub(crate) fn make_router(state: Arc<AppState>, rpc_url: Url) -> Router {
305326 . route ( DEEP_SUPPLY_PATH , get ( deep_supply) )
306327 . route ( SUMMARY_PATH , get ( summary) )
307328 . route ( STATUS_PATH , get ( status) )
308- . with_state ( ( state. clone ( ) , rpc_url ) ) ;
329+ . with_state ( state. clone ( ) ) ;
309330
310331 db_routes
311332 . merge ( rpc_routes)
@@ -320,13 +341,13 @@ async fn health_check() -> StatusCode {
320341/// Get indexer status including checkpoint lag
321342async fn status (
322343 Query ( params) : Query < StatusQueryParams > ,
323- State ( ( state, rpc_url ) ) : State < ( Arc < AppState > , Url ) > ,
344+ State ( state) : State < Arc < AppState > > ,
324345) -> Result < Json < serde_json:: Value > , DeepBookError > {
325346 // Get watermarks from the database
326347 let watermarks = state. reader . get_watermarks ( ) . await ?;
327348
328349 // Get the latest checkpoint from Sui RPC
329- let sui_client = SuiClientBuilder :: default ( ) . build ( rpc_url . as_str ( ) ) . await ?;
350+ let sui_client = state . sui_client ( ) . await ?;
330351 let latest_checkpoint = sui_client
331352 . read_api ( )
332353 . get_latest_checkpoint_sequence_number ( )
@@ -714,7 +735,7 @@ async fn fetch_historical_volume(
714735
715736#[ allow( clippy:: get_first) ]
716737async fn summary (
717- State ( ( state, rpc_url ) ) : State < ( Arc < AppState > , Url ) > ,
738+ State ( state) : State < Arc < AppState > > ,
718739) -> Result < Json < Vec < HashMap < String , Value > > > , DeepBookError > {
719740 // Fetch pools metadata first since it's required for other functions
720741 let pools = state. reader . get_pools ( ) . await ?;
@@ -756,7 +777,7 @@ async fn summary(
756777 orderbook (
757778 Path ( pool_name_clone) ,
758779 Query ( HashMap :: from ( [ ( "level" . to_string ( ) , "1" . to_string ( ) ) ] ) ) ,
759- State ( ( state. clone ( ) , rpc_url . clone ( ) ) ) ,
780+ State ( state. clone ( ) ) ,
760781 )
761782 } )
762783 . collect ( ) ;
@@ -1321,7 +1342,7 @@ pub async fn assets(
13211342async fn orderbook (
13221343 Path ( pool_name) : Path < String > ,
13231344 Query ( params) : Query < HashMap < String , String > > ,
1324- State ( ( state, rpc_url ) ) : State < ( Arc < AppState > , Url ) > ,
1345+ State ( state) : State < Arc < AppState > > ,
13251346) -> Result < Json < HashMap < String , Value > > , DeepBookError > {
13261347 let depth = params
13271348 . get ( "depth" )
@@ -1375,7 +1396,7 @@ async fn orderbook(
13751396
13761397 let pool_address = ObjectID :: from_hex_literal ( & pool_id) ?;
13771398
1378- let sui_client = SuiClientBuilder :: default ( ) . build ( rpc_url . as_str ( ) ) . await ?;
1399+ let sui_client = state . sui_client ( ) . await ?;
13791400 let mut ptb = ProgrammableTransactionBuilder :: new ( ) ;
13801401
13811402 let pool_object: SuiObjectResponse = sui_client
@@ -1531,10 +1552,8 @@ async fn orderbook(
15311552}
15321553
15331554/// DEEP total supply
1534- async fn deep_supply (
1535- State ( ( state, rpc_url) ) : State < ( Arc < AppState > , Url ) > ,
1536- ) -> Result < Json < u64 > , DeepBookError > {
1537- let sui_client = SuiClientBuilder :: default ( ) . build ( rpc_url. as_str ( ) ) . await ?;
1555+ async fn deep_supply ( State ( state) : State < Arc < AppState > > ) -> Result < Json < u64 > , DeepBookError > {
1556+ let sui_client = state. sui_client ( ) . await ?;
15381557 let mut ptb = ProgrammableTransactionBuilder :: new ( ) ;
15391558
15401559 let deep_treasury_object_id = ObjectID :: from_hex_literal ( & state. deep_treasury_id ) ?;
0 commit comments