44//! This client handles authentication, request/response serialization, and basic error handling.
55
66use eyre:: { Context , Result } ;
7- use openzeppelin_relayer:: models:: {
8- relayer:: { CreateRelayerRequest , RelayerResponse } ,
9- ApiResponse ,
10- } ;
7+ use openzeppelin_relayer:: models:: { relayer:: RelayerResponse , ApiResponse } ;
118use reqwest:: Client as HttpClient ;
129use serde:: { Deserialize , Serialize } ;
1310use std:: env;
14- use tracing:: { debug, error, info} ;
15- use uuid:: Uuid ;
1611
1712/// HTTP client for OpenZeppelin Relayer API
1813#[ derive( Debug ) ]
@@ -22,20 +17,6 @@ pub struct RelayerClient {
2217 client : HttpClient ,
2318}
2419
25- /// Generates a deterministic relayer ID from network and signer using UUID v5
26- ///
27- /// Uses UUID v5 with OID namespace to generate a deterministic UUID from
28- /// the network and signer_id combination. This ensures:
29- /// - Same network+signer always generates the same UUID (deterministic)
30- /// - ID is exactly 36 characters (meets validation requirement)
31- /// - Different network+signer combinations generate different UUIDs
32- ///
33- /// Format: UUID v5 based on "{network}:{signer_id}"
34- fn generate_relayer_id ( network : & str , signer_id : & str ) -> String {
35- let name = format ! ( "{}:{}" , network, signer_id) ;
36- Uuid :: new_v5 ( & Uuid :: NAMESPACE_OID , name. as_bytes ( ) ) . to_string ( )
37- }
38-
3920impl RelayerClient {
4021 /// Creates a new RelayerClient from environment variables
4122 ///
@@ -59,78 +40,6 @@ impl RelayerClient {
5940 } )
6041 }
6142
62- /// Checks the health of the relayer service
63- ///
64- /// GET /api/v1/health
65- pub async fn health ( & self ) -> Result < HealthResponse > {
66- let url = format ! ( "{}/api/v1/health" , self . base_url) ;
67-
68- let response = self
69- . client
70- . get ( & url)
71- . header ( "Authorization" , format ! ( "Bearer {}" , self . api_key) )
72- . send ( )
73- . await
74- . wrap_err_with ( || format ! ( "Failed to send request to {}" , url) ) ?;
75-
76- let status = response. status ( ) ;
77- let body = response
78- . text ( )
79- . await
80- . wrap_err ( "Failed to read response body" ) ?;
81-
82- if !status. is_success ( ) {
83- return Err ( eyre:: eyre!(
84- "Health check failed with status {}: {}" ,
85- status,
86- body
87- ) ) ;
88- }
89-
90- // Health endpoint returns plain text "OK"
91- Ok ( HealthResponse {
92- status : body. trim ( ) . to_lowercase ( ) ,
93- } )
94- }
95-
96- /// Creates a new relayer
97- ///
98- /// POST /api/v1/relayers
99- pub async fn create_relayer ( & self , request : CreateRelayerRequest ) -> Result < RelayerResponse > {
100- let url = format ! ( "{}/api/v1/relayers" , self . base_url) ;
101-
102- let response = self
103- . client
104- . post ( & url)
105- . header ( "Authorization" , format ! ( "Bearer {}" , self . api_key) )
106- . json ( & request)
107- . send ( )
108- . await
109- . wrap_err_with ( || format ! ( "Failed to send request to {}" , url) ) ?;
110-
111- let status = response. status ( ) ;
112- let body = response
113- . text ( )
114- . await
115- . wrap_err ( "Failed to read response body" ) ?;
116-
117- if !status. is_success ( ) {
118- return Err ( eyre:: eyre!(
119- "API request failed with status {}: {}" ,
120- status,
121- body
122- ) ) ;
123- }
124-
125- // Parse response
126- let api_response: ApiResponse < RelayerResponse > = serde_json:: from_str ( & body)
127- . wrap_err_with ( || format ! ( "Failed to parse response: {}" , body) ) ?;
128-
129- api_response
130- . data
131- . ok_or_else ( || eyre:: eyre!( "API response missing data field" ) )
132- }
133-
13443 /// Gets a relayer by ID
13544 ///
13645 /// GET /api/v1/relayers/{id}
@@ -256,106 +165,14 @@ impl RelayerClient {
256165 . data
257166 . ok_or_else ( || eyre:: eyre!( "API response missing data field" ) )
258167 }
259-
260- /// Deletes a relayer by ID
261- ///
262- /// DELETE /api/v1/relayers/{id}
263- pub async fn delete_relayer ( & self , relayer_id : & str ) -> Result < ( ) > {
264- let url = format ! ( "{}/api/v1/relayers/{}" , self . base_url, relayer_id) ;
265-
266- let response = self
267- . client
268- . delete ( & url)
269- . header ( "Authorization" , format ! ( "Bearer {}" , self . api_key) )
270- . send ( )
271- . await
272- . wrap_err_with ( || format ! ( "Failed to send request to {}" , url) ) ?;
273-
274- let status = response. status ( ) ;
275-
276- if !status. is_success ( ) {
277- let body = response
278- . text ( )
279- . await
280- . wrap_err ( "Failed to read response body" ) ?;
281- return Err ( eyre:: eyre!(
282- "API request failed with status {}: {}" ,
283- status,
284- body
285- ) ) ;
286- }
287-
288- Ok ( ( ) )
289- }
290-
291- /// Lists all relayers
292- ///
293- /// GET /api/v1/relayers
294- pub async fn list_relayers ( & self ) -> Result < Vec < RelayerResponse > > {
295- let url = format ! ( "{}/api/v1/relayers" , self . base_url) ;
296-
297- let response = self
298- . client
299- . get ( & url)
300- . header ( "Authorization" , format ! ( "Bearer {}" , self . api_key) )
301- . send ( )
302- . await
303- . wrap_err_with ( || format ! ( "Failed to send request to {}" , url) ) ?;
304-
305- let status = response. status ( ) ;
306- let body = response
307- . text ( )
308- . await
309- . wrap_err ( "Failed to read response body" ) ?;
310-
311- if !status. is_success ( ) {
312- return Err ( eyre:: eyre!(
313- "API request failed with status {}: {}" ,
314- status,
315- body
316- ) ) ;
317- }
318-
319- let api_response: ApiResponse < Vec < RelayerResponse > > = serde_json:: from_str ( & body)
320- . wrap_err_with ( || format ! ( "Failed to parse response: {}" , body) ) ?;
321-
322- api_response
323- . data
324- . ok_or_else ( || eyre:: eyre!( "API response missing data field" ) )
325- }
326-
327- /// Deletes all relayers for a specific network
328- ///
329- /// This is a convenience method that lists all relayers and deletes those matching the network
330- pub async fn delete_all_relayers_by_network ( & self , network : & str ) -> Result < usize > {
331- let relayers = self . list_relayers ( ) . await ?;
332-
333- let network_relayers: Vec < _ > = relayers. iter ( ) . filter ( |r| r. network == network) . collect ( ) ;
334-
335- let count = network_relayers. len ( ) ;
336-
337- for relayer in network_relayers {
338- if let Err ( e) = self . delete_relayer ( & relayer. id ) . await {
339- error ! ( relayer_id = %relayer. id, error = %e, "Failed to delete relayer" ) ;
340- }
341- }
342-
343- Ok ( count)
344- }
345168}
346169
347170// ============================================================================
348171// Request/Response Models
349172// ============================================================================
350173
351- // Note: CreateRelayerRequest and RelayerResponse are imported from
352- // openzeppelin_relayer::models::relayer to avoid duplication
353-
354- /// Health check response (not available in src, specific to health endpoint)
355- #[ derive( Debug , Serialize , Deserialize , Clone ) ]
356- pub struct HealthResponse {
357- pub status : String ,
358- }
174+ // Note: RelayerResponse is imported from openzeppelin_relayer::models::relayer
175+ // to avoid duplication
359176
360177/// Transaction response from API (simplified version for integration tests)
361178#[ derive( Debug , Serialize , Deserialize , Clone ) ]
0 commit comments