@@ -36,12 +36,13 @@ use crate::clob::types::request::{
3636} ;
3737use crate :: clob:: types:: response:: {
3838 ApiKeysResponse , BalanceAllowanceResponse , BanStatusResponse , BuilderApiKeyResponse ,
39- BuilderTradeResponse , CancelOrdersResponse , CurrentRewardResponse , FeeRateResponse ,
40- GeoblockResponse , HeartbeatResponse , LastTradePriceResponse , LastTradesPricesResponse ,
41- MarketResponse , MarketRewardResponse , MidpointResponse , MidpointsResponse , NegRiskResponse ,
42- NotificationResponse , OpenOrderResponse , OrderBookSummaryResponse , OrderScoringResponse ,
43- OrdersScoringResponse , Page , PostOrderResponse , PriceHistoryResponse , PriceResponse ,
44- PricesResponse , RewardsPercentagesResponse , SimplifiedMarketResponse , SpreadResponse ,
39+ BuilderFeeRateResponse , BuilderTradeResponse , CancelOrdersResponse , ClobMarketInfoResponse ,
40+ CurrentRewardResponse , FeeRateResponse , GeoblockResponse , HeartbeatResponse ,
41+ LastTradePriceResponse , LastTradesPricesResponse , MarketResponse , MarketRewardResponse ,
42+ MidpointResponse , MidpointsResponse , NegRiskResponse , NotificationResponse ,
43+ OpenOrderResponse , OrderBookSummaryResponse , OrderScoringResponse , OrdersScoringResponse ,
44+ Page , PostOrderResponse , PriceHistoryResponse , PriceResponse , PricesResponse ,
45+ ReadonlyApiKeyResponse , RewardsPercentagesResponse , SimplifiedMarketResponse , SpreadResponse ,
4546 SpreadsResponse , TickSizeResponse , TotalUserEarningResponse , TradeResponse ,
4647 UserEarningResponse , UserRewardsEarningResponse ,
4748} ;
@@ -54,7 +55,7 @@ use crate::clob::types::{
5455} ;
5556use crate :: clob:: types:: { SignableOrder , SignatureType , SignedOrder , TickSize } ;
5657use crate :: error:: { Error , Kind as ErrorKind , Synchronization } ;
57- use crate :: types:: Address ;
58+ use crate :: types:: { Address , B256 } ;
5859use crate :: {
5960 AMOY , POLYGON , Result , Timestamp , ToQueryParams as _, auth, contract_config,
6061 derive_proxy_wallet, derive_safe_wallet,
@@ -222,6 +223,7 @@ impl<S: Signer, K: Kind> AuthenticationBuilder<'_, S, K> {
222223 tick_sizes : inner. tick_sizes ,
223224 neg_risk : inner. neg_risk ,
224225 fee_rate_bps : inner. fee_rate_bps ,
226+ builder_fee_rates : inner. builder_fee_rates ,
225227 funder,
226228 signature_type : self . signature_type . unwrap_or ( SignatureType :: Eoa ) ,
227229 salt_generator : self . salt_generator . unwrap_or ( generate_seed) ,
@@ -405,6 +407,8 @@ struct ClientInner<S: State> {
405407 neg_risk : DashMap < U256 , bool > ,
406408 /// Local cache representing the fee rate in basis points per token ID
407409 fee_rate_bps : DashMap < U256 , u32 > ,
410+ /// Local cache of builder fee rates per builder code
411+ builder_fee_rates : DashMap < B256 , BuilderFeeRateResponse > ,
408412 /// The funder for this [`ClientInner`]. If funder is present, then `signature_type` cannot
409413 /// be [`SignatureType::Eoa`]. Conversely, if funder is absent, then `signature_type` cannot be
410414 /// [`SignatureType::Proxy`] or [`SignatureType::GnosisSafe`].
@@ -513,6 +517,7 @@ impl<S: State> Client<S> {
513517 self . inner . tick_sizes . clear ( ) ;
514518 self . inner . fee_rate_bps . clear ( ) ;
515519 self . inner . neg_risk . clear ( ) ;
520+ self . inner . builder_fee_rates . clear ( ) ;
516521 }
517522
518523 /// Pre-populates the tick size cache for a token, avoiding the HTTP call.
@@ -1170,6 +1175,60 @@ impl<S: State> Client<S> {
11701175 }
11711176 }
11721177
1178+ /// Returns combined CLOB market info for a condition ID.
1179+ ///
1180+ /// This endpoint (`GET /clob-markets/{condition_id}`) returns tick size, neg risk,
1181+ /// fee rate, and token data in a single call. It also populates the local caches
1182+ /// for tick size, neg risk, and fee rate for all tokens in the market.
1183+ ///
1184+ /// # Errors
1185+ ///
1186+ /// Returns an error if the HTTP request fails or the response cannot be parsed.
1187+ pub async fn clob_market_info (
1188+ & self ,
1189+ condition_id : & str ,
1190+ ) -> Result < ClobMarketInfoResponse > {
1191+ let request = self
1192+ . client ( )
1193+ . request (
1194+ Method :: GET ,
1195+ format ! ( "{}clob-markets/{condition_id}" , self . host( ) ) ,
1196+ )
1197+ . build ( ) ?;
1198+
1199+ let response: ClobMarketInfoResponse =
1200+ crate :: request ( & self . inner . client , request, None ) . await ?;
1201+
1202+ // Prime local caches from the response
1203+ for token in & response. tokens {
1204+ self . inner . tick_sizes . insert ( token. token_id , response. min_tick_size ) ;
1205+ self . inner . neg_risk . insert ( token. token_id , response. neg_risk ) ;
1206+ self . inner . fee_rate_bps . insert ( token. token_id , response. fee_rate_bps ) ;
1207+ }
1208+
1209+ Ok ( response)
1210+ }
1211+
1212+ /// Looks up a market by token ID.
1213+ ///
1214+ /// This is used internally for cache priming when the condition ID for a token
1215+ /// is not yet known.
1216+ ///
1217+ /// # Errors
1218+ ///
1219+ /// Returns an error if the HTTP request fails or the response cannot be parsed.
1220+ pub async fn market_by_token ( & self , token_id : U256 ) -> Result < MarketResponse > {
1221+ let request = self
1222+ . client ( )
1223+ . request (
1224+ Method :: GET ,
1225+ format ! ( "{}markets-by-token/{token_id}" , self . host( ) ) ,
1226+ )
1227+ . build ( ) ?;
1228+
1229+ crate :: request ( & self . inner . client , request, None ) . await
1230+ }
1231+
11731232 fn client ( & self ) -> & ReqwestClient {
11741233 & self . inner . client
11751234 }
@@ -1227,6 +1286,7 @@ impl Client<Unauthenticated> {
12271286 tick_sizes : DashMap :: new ( ) ,
12281287 neg_risk : DashMap :: new ( ) ,
12291288 fee_rate_bps : DashMap :: new ( ) ,
1289+ builder_fee_rates : DashMap :: new ( ) ,
12301290 state : Unauthenticated ,
12311291 funder : None ,
12321292 signature_type : SignatureType :: Eoa ,
@@ -1339,6 +1399,7 @@ impl<K: Kind> Client<Authenticated<K>> {
13391399 tick_sizes : inner. tick_sizes ,
13401400 neg_risk : inner. neg_risk ,
13411401 fee_rate_bps : inner. fee_rate_bps ,
1402+ builder_fee_rates : inner. builder_fee_rates ,
13421403 // Reset the order parameters that were previously stored on the client
13431404 funder : None ,
13441405 signature_type : SignatureType :: Eoa ,
@@ -1992,6 +2053,121 @@ impl<K: Kind> Client<Authenticated<K>> {
19922053 crate :: request ( & self . inner . client , request, Some ( headers) ) . await
19932054 }
19942055
2056+ /// Creates a new read-only API key.
2057+ ///
2058+ /// Read-only keys can access account data but cannot place or cancel orders.
2059+ ///
2060+ /// # Errors
2061+ ///
2062+ /// Returns an error if the HTTP request fails or the response cannot be parsed.
2063+ pub async fn create_readonly_api_key ( & self ) -> Result < ReadonlyApiKeyResponse > {
2064+ let request = self
2065+ . client ( )
2066+ . request ( Method :: POST , format ! ( "{}auth/readonly-api-key" , self . host( ) ) )
2067+ . build ( ) ?;
2068+ let headers = self . create_headers ( & request) . await ?;
2069+
2070+ crate :: request ( & self . inner . client , request, Some ( headers) ) . await
2071+ }
2072+
2073+ /// Lists all read-only API keys for the authenticated user.
2074+ ///
2075+ /// # Errors
2076+ ///
2077+ /// Returns an error if the HTTP request fails or the response cannot be parsed.
2078+ pub async fn readonly_api_keys ( & self ) -> Result < Vec < ReadonlyApiKeyResponse > > {
2079+ let request = self
2080+ . client ( )
2081+ . request ( Method :: GET , format ! ( "{}auth/readonly-api-keys" , self . host( ) ) )
2082+ . build ( ) ?;
2083+ let headers = self . create_headers ( & request) . await ?;
2084+
2085+ crate :: request ( & self . inner . client , request, Some ( headers) ) . await
2086+ }
2087+
2088+ /// Deletes a read-only API key.
2089+ ///
2090+ /// # Errors
2091+ ///
2092+ /// Returns an error if the HTTP request fails or the key cannot be deleted.
2093+ pub async fn delete_readonly_api_key ( & self , key : & str ) -> Result < ( ) > {
2094+ let mut request = self
2095+ . client ( )
2096+ . request (
2097+ Method :: DELETE ,
2098+ format ! ( "{}auth/readonly-api-key" , self . host( ) ) ,
2099+ )
2100+ . json ( & serde_json:: json!( { "key" : key } ) )
2101+ . build ( ) ?;
2102+ let headers = self . create_headers ( & request) . await ?;
2103+
2104+ * request. headers_mut ( ) = headers;
2105+ self . inner . client . execute ( request) . await ?;
2106+
2107+ Ok ( ( ) )
2108+ }
2109+
2110+ /// Gets pre-migration orders (legacy V1 orders) for the authenticated user.
2111+ ///
2112+ /// # Errors
2113+ ///
2114+ /// Returns an error if the HTTP request fails or the response cannot be parsed.
2115+ pub async fn pre_migration_orders (
2116+ & self ,
2117+ next_cursor : Option < String > ,
2118+ ) -> Result < Page < OpenOrderResponse > > {
2119+ let cursor = next_cursor
2120+ . map ( |c| format ! ( "?next_cursor={c}" ) )
2121+ . unwrap_or_default ( ) ;
2122+
2123+ let request = self
2124+ . client ( )
2125+ . request (
2126+ Method :: GET ,
2127+ format ! ( "{}data/pre-migration-orders{cursor}" , self . host( ) ) ,
2128+ )
2129+ . build ( ) ?;
2130+ let headers = self . create_headers ( & request) . await ?;
2131+
2132+ crate :: request ( & self . inner . client , request, Some ( headers) ) . await
2133+ }
2134+
2135+ /// Gets the builder fee rate for a given builder code, with local caching.
2136+ ///
2137+ /// The server returns fee rates in basis points. The response contains the raw
2138+ /// BPS values; callers should divide by 10000 to get decimal rates.
2139+ ///
2140+ /// Results are cached per builder code. Use [`Client::invalidate_internal_caches`]
2141+ /// to clear.
2142+ ///
2143+ /// # Errors
2144+ ///
2145+ /// Returns an error if the HTTP request fails or the response cannot be parsed.
2146+ pub async fn builder_fee_rate (
2147+ & self ,
2148+ builder_code : B256 ,
2149+ ) -> Result < BuilderFeeRateResponse > {
2150+ if let Some ( cached) = self . inner . builder_fee_rates . get ( & builder_code) {
2151+ return Ok ( cached. clone ( ) ) ;
2152+ }
2153+
2154+ let request = self
2155+ . client ( )
2156+ . request (
2157+ Method :: GET ,
2158+ format ! ( "{}fees/builder-fees/{builder_code}" , self . host( ) ) ,
2159+ )
2160+ . build ( ) ?;
2161+ let headers = self . create_headers ( & request) . await ?;
2162+
2163+ let response: BuilderFeeRateResponse =
2164+ crate :: request ( & self . inner . client , request, Some ( headers) ) . await ?;
2165+
2166+ self . inner . builder_fee_rates . insert ( builder_code, response. clone ( ) ) ;
2167+
2168+ Ok ( response)
2169+ }
2170+
19952171 /// Creates a new Builder API key for order attribution.
19962172 ///
19972173 /// Builder API keys allow you to attribute orders to your builder account,
@@ -2202,6 +2378,7 @@ impl Client<Authenticated<Normal>> {
22022378 tick_sizes : inner. tick_sizes ,
22032379 neg_risk : inner. neg_risk ,
22042380 fee_rate_bps : inner. fee_rate_bps ,
2381+ builder_fee_rates : inner. builder_fee_rates ,
22052382 funder : inner. funder ,
22062383 signature_type : inner. signature_type ,
22072384 salt_generator : inner. salt_generator ,
0 commit comments