@@ -41,7 +41,20 @@ impl RpcEndpoints {
4141 /// Returns all (alias -> url) pairs
4242 pub fn resolved ( self ) -> ResolvedRpcEndpoints {
4343 ResolvedRpcEndpoints {
44- endpoints : self . endpoints . into_iter ( ) . map ( |( name, e) | ( name, e. resolve ( ) ) ) . collect ( ) ,
44+ endpoints : self
45+ . endpoints
46+ . clone ( )
47+ . into_iter ( )
48+ . map ( |( name, e) | ( name, e. resolve ( ) ) )
49+ . collect ( ) ,
50+ auths : self
51+ . endpoints
52+ . into_iter ( )
53+ . map ( |( name, e) | match e. auth {
54+ Some ( auth) => ( name, auth. resolve ( ) . map ( Some ) ) ,
55+ None => ( name, Ok ( None ) ) ,
56+ } )
57+ . collect ( ) ,
4558 }
4659 }
4760}
@@ -210,6 +223,58 @@ impl From<RpcEndpoint> for RpcEndpointConfig {
210223 }
211224}
212225
226+ /// The auth token to be used for RPC endpoints
227+ /// It works in the same way as the `RpcEndpoint` type, where it can be a raw string or a reference
228+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
229+ pub enum RpcAuth {
230+ Raw ( String ) ,
231+ Env ( String ) ,
232+ }
233+
234+ impl RpcAuth {
235+ /// Returns the auth token this type holds
236+ ///
237+ /// # Error
238+ ///
239+ /// Returns an error if the type holds a reference to an env var and the env var is not set
240+ pub fn resolve ( self ) -> Result < String , UnresolvedEnvVarError > {
241+ match self {
242+ Self :: Raw ( raw_auth) => Ok ( raw_auth) ,
243+ Self :: Env ( var) => interpolate ( & var) ,
244+ }
245+ }
246+ }
247+
248+ impl fmt:: Display for RpcAuth {
249+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
250+ match self {
251+ Self :: Raw ( url) => url. fmt ( f) ,
252+ Self :: Env ( var) => var. fmt ( f) ,
253+ }
254+ }
255+ }
256+
257+ impl Serialize for RpcAuth {
258+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
259+ where
260+ S : Serializer ,
261+ {
262+ serializer. serialize_str ( & self . to_string ( ) )
263+ }
264+ }
265+
266+ impl < ' de > Deserialize < ' de > for RpcAuth {
267+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
268+ where
269+ D : Deserializer < ' de > ,
270+ {
271+ let val = String :: deserialize ( deserializer) ?;
272+ let auth = if RE_PLACEHOLDER . is_match ( & val) { Self :: Env ( val) } else { Self :: Raw ( val) } ;
273+
274+ Ok ( auth)
275+ }
276+ }
277+
213278/// Rpc endpoint configuration variant
214279#[ derive( Debug , Clone , PartialEq , Eq ) ]
215280pub struct RpcEndpointConfig {
@@ -226,6 +291,9 @@ pub struct RpcEndpointConfig {
226291 ///
227292 /// See also <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>
228293 pub compute_units_per_second : Option < u64 > ,
294+
295+ /// Token to be used as authentication
296+ pub auth : Option < RpcAuth > ,
229297}
230298
231299impl RpcEndpointConfig {
@@ -237,7 +305,7 @@ impl RpcEndpointConfig {
237305
238306impl fmt:: Display for RpcEndpointConfig {
239307 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
240- let Self { endpoint, retries, retry_backoff, compute_units_per_second } = self ;
308+ let Self { endpoint, retries, retry_backoff, compute_units_per_second, auth } = self ;
241309
242310 write ! ( f, "{endpoint}" ) ?;
243311
@@ -253,6 +321,10 @@ impl fmt::Display for RpcEndpointConfig {
253321 write ! ( f, ", compute_units_per_second={compute_units_per_second}" ) ?;
254322 }
255323
324+ if let Some ( auth) = auth {
325+ write ! ( f, ", auth={auth}" ) ?;
326+ }
327+
256328 Ok ( ( ) )
257329 }
258330}
@@ -274,6 +346,7 @@ impl Serialize for RpcEndpointConfig {
274346 map. serialize_entry ( "retries" , & self . retries ) ?;
275347 map. serialize_entry ( "retry_backoff" , & self . retry_backoff ) ?;
276348 map. serialize_entry ( "compute_units_per_second" , & self . compute_units_per_second ) ?;
349+ map. serialize_entry ( "auth" , & self . auth ) ?;
277350 map. end ( )
278351 }
279352 }
@@ -299,12 +372,18 @@ impl<'de> Deserialize<'de> for RpcEndpointConfig {
299372 retries : Option < u32 > ,
300373 retry_backoff : Option < u64 > ,
301374 compute_units_per_second : Option < u64 > ,
375+ auth : Option < RpcAuth > ,
302376 }
303377
304- let RpcEndpointConfigInner { endpoint, retries, retry_backoff, compute_units_per_second } =
305- serde_json:: from_value ( value) . map_err ( serde:: de:: Error :: custom) ?;
378+ let RpcEndpointConfigInner {
379+ endpoint,
380+ retries,
381+ retry_backoff,
382+ compute_units_per_second,
383+ auth,
384+ } = serde_json:: from_value ( value) . map_err ( serde:: de:: Error :: custom) ?;
306385
307- Ok ( Self { endpoint, retries, retry_backoff, compute_units_per_second } )
386+ Ok ( Self { endpoint, retries, retry_backoff, compute_units_per_second, auth } )
308387 }
309388}
310389
@@ -321,6 +400,7 @@ impl Default for RpcEndpointConfig {
321400 retries : None ,
322401 retry_backoff : None ,
323402 compute_units_per_second : None ,
403+ auth : None ,
324404 }
325405 }
326406}
@@ -331,6 +411,7 @@ pub struct ResolvedRpcEndpoints {
331411 /// contains all named endpoints and their URL or an error if we failed to resolve the env var
332412 /// alias
333413 endpoints : BTreeMap < String , Result < String , UnresolvedEnvVarError > > ,
414+ auths : BTreeMap < String , Result < Option < String > , UnresolvedEnvVarError > > ,
334415}
335416
336417impl ResolvedRpcEndpoints {
@@ -364,7 +445,8 @@ mod tests {
364445 "endpoint": "http://localhost:8545",
365446 "retries": 5,
366447 "retry_backoff": 250,
367- "compute_units_per_second": 100
448+ "compute_units_per_second": 100,
449+ "auth": "Bearer 123"
368450 }"# ;
369451 let config: RpcEndpointConfig = serde_json:: from_str ( s) . unwrap ( ) ;
370452 assert_eq ! (
@@ -374,6 +456,7 @@ mod tests {
374456 retries: Some ( 5 ) ,
375457 retry_backoff: Some ( 250 ) ,
376458 compute_units_per_second: Some ( 100 ) ,
459+ auth: Some ( RpcAuth :: Raw ( "Bearer 123" . to_string( ) ) ) ,
377460 }
378461 ) ;
379462
@@ -386,6 +469,7 @@ mod tests {
386469 retries: None ,
387470 retry_backoff: None ,
388471 compute_units_per_second: None ,
472+ auth: None ,
389473 }
390474 ) ;
391475 }
0 commit comments