renegade

SDK for interacting with the Renegade darkpool.

 1"""SDK for interacting with the Renegade darkpool."""
 2
 3from .client import (
 4    ExternalMatchClient, ExternalMatchOptions, ExternalMatchClientError,
 5    AssembleExternalMatchOptions, RequestQuoteOptions 
 6)
 7from .http import RelayerHttpClient
 8from .types import ExternalOrder, OrderSide, AtomicMatchApiBundle, SignedExternalQuote
 9
10__all__ = [
11    "AtomicMatchApiBundle",
12    "SignedExternalQuote",
13    "ExternalMatchClient",
14    "ExternalMatchOptions",
15    "AssembleExternalMatchOptions",
16    "RequestQuoteOptions",
17    "ExternalMatchClientError",
18    "RelayerHttpClient",
19    "ExternalOrder",
20    "OrderSide",
21]
class AtomicMatchApiBundle(renegade.types.BaseModelWithConfig):
120class AtomicMatchApiBundle(BaseModelWithConfig):
121    match_result: ApiExternalMatchResult
122    fees: FeeTake
123    receive: ApiExternalAssetTransfer
124    send: ApiExternalAssetTransfer
125    settlement_tx: TxParams

Base model with common configuration

match_result: renegade.types.ApiExternalMatchResult = PydanticUndefined
fees: renegade.types.FeeTake = PydanticUndefined
receive: renegade.types.ApiExternalAssetTransfer = PydanticUndefined
send: renegade.types.ApiExternalAssetTransfer = PydanticUndefined
settlement_tx: web3.types.TxParams = PydanticUndefined
class SignedExternalQuote(renegade.types.BaseModelWithConfig):
115class SignedExternalQuote(BaseModelWithConfig):
116    quote: ApiExternalQuote
117    signature: str
118    gas_sponsorship_info: Optional[SignedGasSponsorshipInfo] = None

Base model with common configuration

quote: renegade.types.ApiExternalQuote = PydanticUndefined
signature: str = PydanticUndefined
gas_sponsorship_info: Optional[renegade.types.SignedGasSponsorshipInfo] = None
class ExternalMatchClient:
191class ExternalMatchClient:
192    """Client for interacting with the Renegade external matching API.
193    
194    This client handles authentication and provides methods for requesting quotes,
195    assembling matches, and executing trades.
196    """
197    
198    def __init__(self, api_key: str, api_secret: str, base_url: str):
199        """Initialize a new ExternalMatchClient.
200        
201        Args:
202            api_key: The API key for authentication
203            api_secret: The API secret for request signing
204            base_url: The base URL of the Renegade API
205        """
206        self.api_key = api_key
207        self.http_client = RelayerHttpClient(base_url, api_secret)
208
209    @classmethod
210    def new_arbitrum_sepolia_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
211        """Create a new client configured for the Arbitrum Sepolia testnet.
212
213        Args:
214            api_key: The API key for authentication
215            api_secret: The API secret for request signing
216
217        Returns:
218            A new ExternalMatchClient configured for Arbitrum Sepolia
219        """
220        return cls(api_key, api_secret, ARBITRUM_SEPOLIA_BASE_URL)
221
222    @classmethod
223    def new_base_sepolia_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
224        """Create a new client configured for Base Sepolia testnet.
225
226        Args:
227            api_key: The API key for authentication
228            api_secret: The API secret for request signing
229
230        Returns:
231            A new ExternalMatchClient configured for Base Sepolia
232        """
233        return cls(api_key, api_secret, BASE_SEPOLIA_BASE_URL)
234
235    @classmethod
236    @deprecated(version="0.1.8", reason="Use new_arbitrum_sepolia_client instead")
237    def new_sepolia_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
238        """Create a new client configured for the Arbitrum Sepolia testnet.
239
240        Args:
241            api_key: The API key for authentication
242            api_secret: The API secret for request signing
243
244        Returns:
245            A new ExternalMatchClient configured for Arbitrum Sepolia
246        """
247        return cls.new_arbitrum_sepolia_client(api_key, api_secret)
248
249    @classmethod
250    def new_arbitrum_one_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
251        """Create a new client configured for Arbitrum One.
252
253        Args:
254            api_key: The API key for authentication
255            api_secret: The API secret for request signing
256
257        Returns:
258            A new ExternalMatchClient configured for Arbitrum One
259        """
260        return cls(api_key, api_secret, ARBITRUM_ONE_BASE_URL)
261    
262    @classmethod
263    def new_base_mainnet_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
264        """Create a new client configured for Base mainnet.
265
266        Args:
267            api_key: The API key for authentication
268            api_secret: The API secret for request signing
269
270        Returns:
271            A new ExternalMatchClient configured for Base mainnet
272        """
273        return cls(api_key, api_secret, BASE_MAINNET_BASE_URL)
274
275    @classmethod
276    @deprecated(version="0.1.8", reason="Use new_arbitrum_one_client instead")
277    def new_mainnet_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
278        """Create a new client configured for mainnet.
279
280        Args:
281            api_key: The API key for authentication
282            api_secret: The API secret for request signing
283
284        Returns:
285            A new ExternalMatchClient configured for mainnet
286        """
287        return cls.new_arbitrum_one_client(api_key, api_secret)
288
289    async def request_quote(self, order: ExternalOrder) -> Optional[SignedExternalQuote]:
290        """Request a quote for the given order.
291        
292        Args:
293            order: The order to request a quote for
294            
295        Returns:
296            A signed quote if one is available, None otherwise
297            
298        Raises:
299            ExternalMatchClientError: If the request fails
300        """
301        return await self.request_quote_with_options(order, RequestQuoteOptions())
302
303    def request_quote_sync(self, order: ExternalOrder) -> Optional[SignedExternalQuote]:
304        """Synchronous version of request_quote method.
305        
306        Args:
307            order: The order to request a quote for
308            
309        Returns:
310            A signed quote if one is available, None otherwise
311            
312        Raises:
313            ExternalMatchClientError: If the request fails
314        """
315        return self.request_quote_with_options_sync(order, RequestQuoteOptions())
316
317    async def request_quote_with_options(
318        self,
319        order: ExternalOrder,
320        options: RequestQuoteOptions
321    ) -> Optional[SignedExternalQuote]:
322        """Request a quote for the given order with custom options.
323
324        Args:
325            order: The order to request a quote for
326            options: Custom options for the quote request
327
328        Returns:
329            A signed quote if one is available, None otherwise
330
331        Raises:
332            ExternalMatchClientError: If the request fails
333        """
334        request = ExternalQuoteRequest(external_order=order)
335
336        path = options.build_request_path()
337        headers = self._get_headers()
338        response = await self.http_client.post_with_headers(path, request.model_dump(), headers)
339        quote_resp = self._handle_optional_response(response)
340
341        if quote_resp == None:
342            return None
343
344        quote_resp = ExternalQuoteResponse(**quote_resp)
345        signed_quote = SignedExternalQuote(
346            quote=quote_resp.signed_quote.quote,
347            signature=quote_resp.signed_quote.signature,
348            gas_sponsorship_info=quote_resp.gas_sponsorship_info
349        )
350
351        return signed_quote
352
353    def request_quote_with_options_sync(
354        self,
355        order: ExternalOrder,
356        options: RequestQuoteOptions
357    ) -> Optional[ExternalQuoteResponse]:
358        """Synchronous version of request_quote_with_options method.
359
360        Args:
361            order: The order to request a quote for
362            options: Custom options for the quote request
363
364        Returns:
365            A signed quote if one is available, None otherwise
366
367        Raises:
368            ExternalMatchClientError: If the request fails
369        """
370        request = ExternalQuoteRequest(external_order=order)
371
372        path = options.build_request_path()
373        headers = self._get_headers()
374        response = self.http_client.post_with_headers_sync(path, request.model_dump(), headers)
375        quote_resp = self._handle_optional_response(response)
376
377        if quote_resp == None:
378            return None
379
380        quote_resp = ExternalQuoteResponse(**quote_resp)
381        signed_quote = SignedExternalQuote(
382            quote=quote_resp.signed_quote.quote,
383            signature=quote_resp.signed_quote.signature,
384            gas_sponsorship_info=quote_resp.gas_sponsorship_info
385        )
386
387        return signed_quote
388
389    async def assemble_quote(self, quote: SignedExternalQuote) -> Optional[ExternalMatchResponse]:
390        """Assemble a quote into a match bundle with default options.
391        
392        Args:
393            quote: The signed quote to assemble
394            
395        Returns:
396            A match bundle if assembly succeeds, None otherwise
397            
398        Raises:
399            ExternalMatchClientError: If the request fails
400        """
401        return await self.assemble_quote_with_options(quote, AssembleExternalMatchOptions())
402
403    def assemble_quote_sync(self, quote: SignedExternalQuote) -> Optional[ExternalMatchResponse]:
404        """Synchronous version of assemble_quote method.
405        
406        Args:
407            quote: The signed quote to assemble
408            
409        Returns:
410            A match bundle if assembly succeeds, None otherwise
411            
412        Raises:
413            ExternalMatchClientError: If the request fails
414        """
415        return self.assemble_quote_with_options_sync(quote, AssembleExternalMatchOptions())
416
417    async def assemble_quote_with_options(
418        self, 
419        quote: SignedExternalQuote, 
420        options: AssembleExternalMatchOptions
421    ) -> Optional[ExternalMatchResponse]:
422        """Assemble a quote into a match bundle with custom options.
423        
424        Args:
425            quote: The signed quote to assemble
426            options: Custom options for quote assembly
427            
428        Returns:
429            A match bundle if assembly succeeds, None otherwise
430            
431        Raises:
432            ExternalMatchClientError: If the request fails
433        """
434        signed_quote = ApiSignedExternalQuote(
435            quote=quote.quote,
436            signature=quote.signature,
437        )
438        request = AssembleExternalMatchRequest(
439            do_gas_estimation=options.do_gas_estimation,
440            allow_shared=options.allow_shared,
441            receiver_address=options.receiver_address,
442            signed_quote=signed_quote,
443            updated_order=options.updated_order,
444        )
445
446        path = options.build_request_path()
447        headers = self._get_headers()
448        response = await self.http_client.post_with_headers(path, request.model_dump(), headers)
449        match_resp = self._handle_optional_response(response)
450        if match_resp:
451            return ExternalMatchResponse(**match_resp)
452
453        return None
454
455    def assemble_quote_with_options_sync(
456        self, 
457        quote: SignedExternalQuote, 
458        options: AssembleExternalMatchOptions
459    ) -> Optional[ExternalMatchResponse]:
460        """Synchronous version of assemble_quote_with_options method.
461        
462        Args:
463            quote: The signed quote to assemble
464            options: Custom options for quote assembly
465            
466        Returns:
467            A match bundle if assembly succeeds, None otherwise
468            
469        Raises:
470            ExternalMatchClientError: If the request fails
471        """
472        signed_quote = ApiSignedExternalQuote(
473            quote=quote.quote,
474            signature=quote.signature,
475        )
476        request = AssembleExternalMatchRequest(
477            do_gas_estimation=options.do_gas_estimation,
478            receiver_address=options.receiver_address,
479            signed_quote=signed_quote,
480            updated_order=options.updated_order,
481        )
482
483        path = options.build_request_path()
484        headers = self._get_headers()
485        response = self.http_client.post_with_headers_sync(path, request.model_dump(), headers)
486        match_resp = self._handle_optional_response(response)
487        if match_resp:
488            return ExternalMatchResponse(**match_resp)
489
490        return None
491
492    def _get_headers(self) -> Headers:
493        """Get the headers required for API requests.
494        
495        Returns:
496            Headers containing the API key and SDK version
497        """
498        headers = Headers()
499        headers[RENEGADE_API_KEY_HEADER] = self.api_key
500        headers[RENEGADE_SDK_VERSION_HEADER] = _get_sdk_version()
501        return headers
502
503    def _handle_optional_response(self, response: Response) -> Optional[dict]:
504        """Handle an API response that may be empty.
505        
506        Args:
507            response: The API response to handle
508            
509        Returns:
510            The response data if present, None for 204 responses
511            
512        Raises:
513            ExternalMatchClientError: If the response indicates an error
514        """
515        if response.status_code == 204:  # NO_CONTENT
516            return None
517        elif response.status_code == 200:  # OK
518            return response.json()
519        else:
520            raise ExternalMatchClientError(
521                response.text,
522                status_code=response.status_code
523            ) 

Client for interacting with the Renegade external matching API.

This client handles authentication and provides methods for requesting quotes, assembling matches, and executing trades.

ExternalMatchClient(api_key: str, api_secret: str, base_url: str)
198    def __init__(self, api_key: str, api_secret: str, base_url: str):
199        """Initialize a new ExternalMatchClient.
200        
201        Args:
202            api_key: The API key for authentication
203            api_secret: The API secret for request signing
204            base_url: The base URL of the Renegade API
205        """
206        self.api_key = api_key
207        self.http_client = RelayerHttpClient(base_url, api_secret)

Initialize a new ExternalMatchClient.

Args: api_key: The API key for authentication api_secret: The API secret for request signing base_url: The base URL of the Renegade API

api_key
http_client
@classmethod
def new_arbitrum_sepolia_client( cls, api_key: str, api_secret: str) -> ExternalMatchClient:
209    @classmethod
210    def new_arbitrum_sepolia_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
211        """Create a new client configured for the Arbitrum Sepolia testnet.
212
213        Args:
214            api_key: The API key for authentication
215            api_secret: The API secret for request signing
216
217        Returns:
218            A new ExternalMatchClient configured for Arbitrum Sepolia
219        """
220        return cls(api_key, api_secret, ARBITRUM_SEPOLIA_BASE_URL)

Create a new client configured for the Arbitrum Sepolia testnet.

Args: api_key: The API key for authentication api_secret: The API secret for request signing

Returns: A new ExternalMatchClient configured for Arbitrum Sepolia

@classmethod
def new_base_sepolia_client( cls, api_key: str, api_secret: str) -> ExternalMatchClient:
222    @classmethod
223    def new_base_sepolia_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
224        """Create a new client configured for Base Sepolia testnet.
225
226        Args:
227            api_key: The API key for authentication
228            api_secret: The API secret for request signing
229
230        Returns:
231            A new ExternalMatchClient configured for Base Sepolia
232        """
233        return cls(api_key, api_secret, BASE_SEPOLIA_BASE_URL)

Create a new client configured for Base Sepolia testnet.

Args: api_key: The API key for authentication api_secret: The API secret for request signing

Returns: A new ExternalMatchClient configured for Base Sepolia

@classmethod
@deprecated(version='0.1.8', reason='Use new_arbitrum_sepolia_client instead')
def new_sepolia_client( cls, api_key: str, api_secret: str) -> ExternalMatchClient:
235    @classmethod
236    @deprecated(version="0.1.8", reason="Use new_arbitrum_sepolia_client instead")
237    def new_sepolia_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
238        """Create a new client configured for the Arbitrum Sepolia testnet.
239
240        Args:
241            api_key: The API key for authentication
242            api_secret: The API secret for request signing
243
244        Returns:
245            A new ExternalMatchClient configured for Arbitrum Sepolia
246        """
247        return cls.new_arbitrum_sepolia_client(api_key, api_secret)

Create a new client configured for the Arbitrum Sepolia testnet.

Args: api_key: The API key for authentication api_secret: The API secret for request signing

Returns: A new ExternalMatchClient configured for Arbitrum Sepolia

@classmethod
def new_arbitrum_one_client( cls, api_key: str, api_secret: str) -> ExternalMatchClient:
249    @classmethod
250    def new_arbitrum_one_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
251        """Create a new client configured for Arbitrum One.
252
253        Args:
254            api_key: The API key for authentication
255            api_secret: The API secret for request signing
256
257        Returns:
258            A new ExternalMatchClient configured for Arbitrum One
259        """
260        return cls(api_key, api_secret, ARBITRUM_ONE_BASE_URL)

Create a new client configured for Arbitrum One.

Args: api_key: The API key for authentication api_secret: The API secret for request signing

Returns: A new ExternalMatchClient configured for Arbitrum One

@classmethod
def new_base_mainnet_client( cls, api_key: str, api_secret: str) -> ExternalMatchClient:
262    @classmethod
263    def new_base_mainnet_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
264        """Create a new client configured for Base mainnet.
265
266        Args:
267            api_key: The API key for authentication
268            api_secret: The API secret for request signing
269
270        Returns:
271            A new ExternalMatchClient configured for Base mainnet
272        """
273        return cls(api_key, api_secret, BASE_MAINNET_BASE_URL)

Create a new client configured for Base mainnet.

Args: api_key: The API key for authentication api_secret: The API secret for request signing

Returns: A new ExternalMatchClient configured for Base mainnet

@classmethod
@deprecated(version='0.1.8', reason='Use new_arbitrum_one_client instead')
def new_mainnet_client( cls, api_key: str, api_secret: str) -> ExternalMatchClient:
275    @classmethod
276    @deprecated(version="0.1.8", reason="Use new_arbitrum_one_client instead")
277    def new_mainnet_client(cls, api_key: str, api_secret: str) -> "ExternalMatchClient":
278        """Create a new client configured for mainnet.
279
280        Args:
281            api_key: The API key for authentication
282            api_secret: The API secret for request signing
283
284        Returns:
285            A new ExternalMatchClient configured for mainnet
286        """
287        return cls.new_arbitrum_one_client(api_key, api_secret)

Create a new client configured for mainnet.

Args: api_key: The API key for authentication api_secret: The API secret for request signing

Returns: A new ExternalMatchClient configured for mainnet

async def request_quote( self, order: ExternalOrder) -> Optional[SignedExternalQuote]:
289    async def request_quote(self, order: ExternalOrder) -> Optional[SignedExternalQuote]:
290        """Request a quote for the given order.
291        
292        Args:
293            order: The order to request a quote for
294            
295        Returns:
296            A signed quote if one is available, None otherwise
297            
298        Raises:
299            ExternalMatchClientError: If the request fails
300        """
301        return await self.request_quote_with_options(order, RequestQuoteOptions())

Request a quote for the given order.

Args: order: The order to request a quote for

Returns: A signed quote if one is available, None otherwise

Raises: ExternalMatchClientError: If the request fails

def request_quote_sync( self, order: ExternalOrder) -> Optional[SignedExternalQuote]:
303    def request_quote_sync(self, order: ExternalOrder) -> Optional[SignedExternalQuote]:
304        """Synchronous version of request_quote method.
305        
306        Args:
307            order: The order to request a quote for
308            
309        Returns:
310            A signed quote if one is available, None otherwise
311            
312        Raises:
313            ExternalMatchClientError: If the request fails
314        """
315        return self.request_quote_with_options_sync(order, RequestQuoteOptions())

Synchronous version of request_quote method.

Args: order: The order to request a quote for

Returns: A signed quote if one is available, None otherwise

Raises: ExternalMatchClientError: If the request fails

async def request_quote_with_options( self, order: ExternalOrder, options: RequestQuoteOptions) -> Optional[SignedExternalQuote]:
317    async def request_quote_with_options(
318        self,
319        order: ExternalOrder,
320        options: RequestQuoteOptions
321    ) -> Optional[SignedExternalQuote]:
322        """Request a quote for the given order with custom options.
323
324        Args:
325            order: The order to request a quote for
326            options: Custom options for the quote request
327
328        Returns:
329            A signed quote if one is available, None otherwise
330
331        Raises:
332            ExternalMatchClientError: If the request fails
333        """
334        request = ExternalQuoteRequest(external_order=order)
335
336        path = options.build_request_path()
337        headers = self._get_headers()
338        response = await self.http_client.post_with_headers(path, request.model_dump(), headers)
339        quote_resp = self._handle_optional_response(response)
340
341        if quote_resp == None:
342            return None
343
344        quote_resp = ExternalQuoteResponse(**quote_resp)
345        signed_quote = SignedExternalQuote(
346            quote=quote_resp.signed_quote.quote,
347            signature=quote_resp.signed_quote.signature,
348            gas_sponsorship_info=quote_resp.gas_sponsorship_info
349        )
350
351        return signed_quote

Request a quote for the given order with custom options.

Args: order: The order to request a quote for options: Custom options for the quote request

Returns: A signed quote if one is available, None otherwise

Raises: ExternalMatchClientError: If the request fails

def request_quote_with_options_sync( self, order: ExternalOrder, options: RequestQuoteOptions) -> Optional[renegade.types.ExternalQuoteResponse]:
353    def request_quote_with_options_sync(
354        self,
355        order: ExternalOrder,
356        options: RequestQuoteOptions
357    ) -> Optional[ExternalQuoteResponse]:
358        """Synchronous version of request_quote_with_options method.
359
360        Args:
361            order: The order to request a quote for
362            options: Custom options for the quote request
363
364        Returns:
365            A signed quote if one is available, None otherwise
366
367        Raises:
368            ExternalMatchClientError: If the request fails
369        """
370        request = ExternalQuoteRequest(external_order=order)
371
372        path = options.build_request_path()
373        headers = self._get_headers()
374        response = self.http_client.post_with_headers_sync(path, request.model_dump(), headers)
375        quote_resp = self._handle_optional_response(response)
376
377        if quote_resp == None:
378            return None
379
380        quote_resp = ExternalQuoteResponse(**quote_resp)
381        signed_quote = SignedExternalQuote(
382            quote=quote_resp.signed_quote.quote,
383            signature=quote_resp.signed_quote.signature,
384            gas_sponsorship_info=quote_resp.gas_sponsorship_info
385        )
386
387        return signed_quote

Synchronous version of request_quote_with_options method.

Args: order: The order to request a quote for options: Custom options for the quote request

Returns: A signed quote if one is available, None otherwise

Raises: ExternalMatchClientError: If the request fails

async def assemble_quote( self, quote: SignedExternalQuote) -> Optional[renegade.types.ExternalMatchResponse]:
389    async def assemble_quote(self, quote: SignedExternalQuote) -> Optional[ExternalMatchResponse]:
390        """Assemble a quote into a match bundle with default options.
391        
392        Args:
393            quote: The signed quote to assemble
394            
395        Returns:
396            A match bundle if assembly succeeds, None otherwise
397            
398        Raises:
399            ExternalMatchClientError: If the request fails
400        """
401        return await self.assemble_quote_with_options(quote, AssembleExternalMatchOptions())

Assemble a quote into a match bundle with default options.

Args: quote: The signed quote to assemble

Returns: A match bundle if assembly succeeds, None otherwise

Raises: ExternalMatchClientError: If the request fails

def assemble_quote_sync( self, quote: SignedExternalQuote) -> Optional[renegade.types.ExternalMatchResponse]:
403    def assemble_quote_sync(self, quote: SignedExternalQuote) -> Optional[ExternalMatchResponse]:
404        """Synchronous version of assemble_quote method.
405        
406        Args:
407            quote: The signed quote to assemble
408            
409        Returns:
410            A match bundle if assembly succeeds, None otherwise
411            
412        Raises:
413            ExternalMatchClientError: If the request fails
414        """
415        return self.assemble_quote_with_options_sync(quote, AssembleExternalMatchOptions())

Synchronous version of assemble_quote method.

Args: quote: The signed quote to assemble

Returns: A match bundle if assembly succeeds, None otherwise

Raises: ExternalMatchClientError: If the request fails

async def assemble_quote_with_options( self, quote: SignedExternalQuote, options: AssembleExternalMatchOptions) -> Optional[renegade.types.ExternalMatchResponse]:
417    async def assemble_quote_with_options(
418        self, 
419        quote: SignedExternalQuote, 
420        options: AssembleExternalMatchOptions
421    ) -> Optional[ExternalMatchResponse]:
422        """Assemble a quote into a match bundle with custom options.
423        
424        Args:
425            quote: The signed quote to assemble
426            options: Custom options for quote assembly
427            
428        Returns:
429            A match bundle if assembly succeeds, None otherwise
430            
431        Raises:
432            ExternalMatchClientError: If the request fails
433        """
434        signed_quote = ApiSignedExternalQuote(
435            quote=quote.quote,
436            signature=quote.signature,
437        )
438        request = AssembleExternalMatchRequest(
439            do_gas_estimation=options.do_gas_estimation,
440            allow_shared=options.allow_shared,
441            receiver_address=options.receiver_address,
442            signed_quote=signed_quote,
443            updated_order=options.updated_order,
444        )
445
446        path = options.build_request_path()
447        headers = self._get_headers()
448        response = await self.http_client.post_with_headers(path, request.model_dump(), headers)
449        match_resp = self._handle_optional_response(response)
450        if match_resp:
451            return ExternalMatchResponse(**match_resp)
452
453        return None

Assemble a quote into a match bundle with custom options.

Args: quote: The signed quote to assemble options: Custom options for quote assembly

Returns: A match bundle if assembly succeeds, None otherwise

Raises: ExternalMatchClientError: If the request fails

def assemble_quote_with_options_sync( self, quote: SignedExternalQuote, options: AssembleExternalMatchOptions) -> Optional[renegade.types.ExternalMatchResponse]:
455    def assemble_quote_with_options_sync(
456        self, 
457        quote: SignedExternalQuote, 
458        options: AssembleExternalMatchOptions
459    ) -> Optional[ExternalMatchResponse]:
460        """Synchronous version of assemble_quote_with_options method.
461        
462        Args:
463            quote: The signed quote to assemble
464            options: Custom options for quote assembly
465            
466        Returns:
467            A match bundle if assembly succeeds, None otherwise
468            
469        Raises:
470            ExternalMatchClientError: If the request fails
471        """
472        signed_quote = ApiSignedExternalQuote(
473            quote=quote.quote,
474            signature=quote.signature,
475        )
476        request = AssembleExternalMatchRequest(
477            do_gas_estimation=options.do_gas_estimation,
478            receiver_address=options.receiver_address,
479            signed_quote=signed_quote,
480            updated_order=options.updated_order,
481        )
482
483        path = options.build_request_path()
484        headers = self._get_headers()
485        response = self.http_client.post_with_headers_sync(path, request.model_dump(), headers)
486        match_resp = self._handle_optional_response(response)
487        if match_resp:
488            return ExternalMatchResponse(**match_resp)
489
490        return None

Synchronous version of assemble_quote_with_options method.

Args: quote: The signed quote to assemble options: Custom options for quote assembly

Returns: A match bundle if assembly succeeds, None otherwise

Raises: ExternalMatchClientError: If the request fails

@dataclass
class ExternalMatchOptions:
56@dataclass
57class ExternalMatchOptions:
58    do_gas_estimation: bool = False
59    receiver_address: Optional[str] = None
60    request_gas_sponsorship: bool = False
61    gas_refund_address: Optional[str] = None
62
63    @classmethod
64    def new(cls) -> "ExternalMatchOptions":
65        return cls()
66
67    def with_gas_estimation(self, do_gas_estimation: bool) -> "ExternalMatchOptions":
68        self.do_gas_estimation = do_gas_estimation
69        return self
70
71    def with_receiver_address(self, receiver_address: str) -> "ExternalMatchOptions":
72        self.receiver_address = receiver_address
73        return self
74
75    def with_gas_sponsorship(self, request_gas_sponsorship: bool, gas_refund_address: Optional[str] = None) -> "ExternalMatchOptions":
76        self.request_gas_sponsorship = request_gas_sponsorship
77        self.gas_refund_address = gas_refund_address
78        return self 
79
80    def with_updated_order(self, updated_order: ExternalOrder) -> "ExternalMatchOptions":
81        self.updated_order = updated_order
82        return self
83
84    def build_request_path(self) -> str:
85        """
86        Builds the path at which the request will be sent, with query params 
87        """
88        disable_sponsorship_str = str(not self.request_gas_sponsorship).lower()
89        path = f"{REQUEST_EXTERNAL_MATCH_ROUTE}?{DISABLE_GAS_SPONSORSHIP_QUERY_PARAM}={disable_sponsorship_str}"
90        if self.gas_refund_address:
91            path += f"&{GAS_REFUND_ADDRESS_QUERY_PARAM}={self.gas_refund_address}"
92
93        return path
ExternalMatchOptions( do_gas_estimation: bool = False, receiver_address: Optional[str] = None, request_gas_sponsorship: bool = False, gas_refund_address: Optional[str] = None)
do_gas_estimation: bool = False
receiver_address: Optional[str] = None
request_gas_sponsorship: bool = False
gas_refund_address: Optional[str] = None
@classmethod
def new(cls) -> ExternalMatchOptions:
63    @classmethod
64    def new(cls) -> "ExternalMatchOptions":
65        return cls()
def with_gas_estimation(self, do_gas_estimation: bool) -> ExternalMatchOptions:
67    def with_gas_estimation(self, do_gas_estimation: bool) -> "ExternalMatchOptions":
68        self.do_gas_estimation = do_gas_estimation
69        return self
def with_receiver_address(self, receiver_address: str) -> ExternalMatchOptions:
71    def with_receiver_address(self, receiver_address: str) -> "ExternalMatchOptions":
72        self.receiver_address = receiver_address
73        return self
def with_gas_sponsorship( self, request_gas_sponsorship: bool, gas_refund_address: Optional[str] = None) -> ExternalMatchOptions:
75    def with_gas_sponsorship(self, request_gas_sponsorship: bool, gas_refund_address: Optional[str] = None) -> "ExternalMatchOptions":
76        self.request_gas_sponsorship = request_gas_sponsorship
77        self.gas_refund_address = gas_refund_address
78        return self 
def with_updated_order( self, updated_order: ExternalOrder) -> ExternalMatchOptions:
80    def with_updated_order(self, updated_order: ExternalOrder) -> "ExternalMatchOptions":
81        self.updated_order = updated_order
82        return self
def build_request_path(self) -> str:
84    def build_request_path(self) -> str:
85        """
86        Builds the path at which the request will be sent, with query params 
87        """
88        disable_sponsorship_str = str(not self.request_gas_sponsorship).lower()
89        path = f"{REQUEST_EXTERNAL_MATCH_ROUTE}?{DISABLE_GAS_SPONSORSHIP_QUERY_PARAM}={disable_sponsorship_str}"
90        if self.gas_refund_address:
91            path += f"&{GAS_REFUND_ADDRESS_QUERY_PARAM}={self.gas_refund_address}"
92
93        return path

Builds the path at which the request will be sent, with query params

@dataclass
class AssembleExternalMatchOptions:
131@dataclass
132class AssembleExternalMatchOptions:
133    do_gas_estimation: bool = False
134    allow_shared: bool = False
135    receiver_address: Optional[str] = None
136    updated_order: Optional[ExternalOrder] = None
137    request_gas_sponsorship: bool = False
138    gas_refund_address: Optional[str] = None
139
140    @classmethod
141    def new(cls) -> "AssembleExternalMatchOptions":
142        return cls()
143
144    def with_gas_estimation(self, do_gas_estimation: bool) -> "AssembleExternalMatchOptions":
145        self.do_gas_estimation = do_gas_estimation
146        return self
147    
148    def with_allow_shared(self, allow_shared: bool) -> "AssembleExternalMatchOptions":
149        self.allow_shared = allow_shared
150        return self
151
152    def with_receiver_address(self, receiver_address: str) -> "AssembleExternalMatchOptions":
153        self.receiver_address = receiver_address
154        return self
155
156    def with_updated_order(self, updated_order: ExternalOrder) -> "AssembleExternalMatchOptions":
157        self.updated_order = updated_order
158        return self
159
160    @deprecated(version="0.1.2", reason="Request gas sponsorship when requesting a quote instead")
161    def with_gas_sponsorship(self, request_gas_sponsorship: bool) -> "AssembleExternalMatchOptions":
162        self.request_gas_sponsorship = request_gas_sponsorship
163        return self
164
165    @deprecated(version="0.1.2", reason="Request gas sponsorship when requesting a quote instead")
166    def with_gas_refund_address(self, gas_refund_address: str) -> "AssembleExternalMatchOptions":
167        self.gas_refund_address = gas_refund_address
168        return self
169
170    def build_request_path(self) -> str:
171        """
172        Builds the path at which the request will be sent, with query params 
173        """
174        path = ASSEMBLE_EXTERNAL_MATCH_ROUTE
175        if self.request_gas_sponsorship:
176            # We only write this query parameter if it was explicitly set. The
177            # expectation of the auth server is that when gas sponsorship is
178            # requested at the quote stage, there should be no query parameters
179            # at all in the assemble request.
180            disable_sponsorship_str = str(not self.request_gas_sponsorship).lower()
181            path += f"?{DISABLE_GAS_SPONSORSHIP_QUERY_PARAM}={disable_sponsorship_str}"
182        if self.gas_refund_address:
183            path += f"&{GAS_REFUND_ADDRESS_QUERY_PARAM}={self.gas_refund_address}"
184
185        return path
AssembleExternalMatchOptions( do_gas_estimation: bool = False, allow_shared: bool = False, receiver_address: Optional[str] = None, updated_order: Optional[ExternalOrder] = None, request_gas_sponsorship: bool = False, gas_refund_address: Optional[str] = None)
do_gas_estimation: bool = False
allow_shared: bool = False
receiver_address: Optional[str] = None
updated_order: Optional[ExternalOrder] = None
request_gas_sponsorship: bool = False
gas_refund_address: Optional[str] = None
@classmethod
def new(cls) -> AssembleExternalMatchOptions:
140    @classmethod
141    def new(cls) -> "AssembleExternalMatchOptions":
142        return cls()
def with_gas_estimation( self, do_gas_estimation: bool) -> AssembleExternalMatchOptions:
144    def with_gas_estimation(self, do_gas_estimation: bool) -> "AssembleExternalMatchOptions":
145        self.do_gas_estimation = do_gas_estimation
146        return self
def with_allow_shared(self, allow_shared: bool) -> AssembleExternalMatchOptions:
148    def with_allow_shared(self, allow_shared: bool) -> "AssembleExternalMatchOptions":
149        self.allow_shared = allow_shared
150        return self
def with_receiver_address( self, receiver_address: str) -> AssembleExternalMatchOptions:
152    def with_receiver_address(self, receiver_address: str) -> "AssembleExternalMatchOptions":
153        self.receiver_address = receiver_address
154        return self
def with_updated_order( self, updated_order: ExternalOrder) -> AssembleExternalMatchOptions:
156    def with_updated_order(self, updated_order: ExternalOrder) -> "AssembleExternalMatchOptions":
157        self.updated_order = updated_order
158        return self
@deprecated(version='0.1.2', reason='Request gas sponsorship when requesting a quote instead')
def with_gas_sponsorship( self, request_gas_sponsorship: bool) -> AssembleExternalMatchOptions:
160    @deprecated(version="0.1.2", reason="Request gas sponsorship when requesting a quote instead")
161    def with_gas_sponsorship(self, request_gas_sponsorship: bool) -> "AssembleExternalMatchOptions":
162        self.request_gas_sponsorship = request_gas_sponsorship
163        return self
@deprecated(version='0.1.2', reason='Request gas sponsorship when requesting a quote instead')
def with_gas_refund_address( self, gas_refund_address: str) -> AssembleExternalMatchOptions:
165    @deprecated(version="0.1.2", reason="Request gas sponsorship when requesting a quote instead")
166    def with_gas_refund_address(self, gas_refund_address: str) -> "AssembleExternalMatchOptions":
167        self.gas_refund_address = gas_refund_address
168        return self
def build_request_path(self) -> str:
170    def build_request_path(self) -> str:
171        """
172        Builds the path at which the request will be sent, with query params 
173        """
174        path = ASSEMBLE_EXTERNAL_MATCH_ROUTE
175        if self.request_gas_sponsorship:
176            # We only write this query parameter if it was explicitly set. The
177            # expectation of the auth server is that when gas sponsorship is
178            # requested at the quote stage, there should be no query parameters
179            # at all in the assemble request.
180            disable_sponsorship_str = str(not self.request_gas_sponsorship).lower()
181            path += f"?{DISABLE_GAS_SPONSORSHIP_QUERY_PARAM}={disable_sponsorship_str}"
182        if self.gas_refund_address:
183            path += f"&{GAS_REFUND_ADDRESS_QUERY_PARAM}={self.gas_refund_address}"
184
185        return path

Builds the path at which the request will be sent, with query params

@dataclass
class RequestQuoteOptions:
 95@dataclass
 96class RequestQuoteOptions:
 97    disable_gas_sponsorship: bool = False
 98    gas_refund_address: Optional[str] = None
 99    refund_native_eth: bool = False
100
101    @classmethod
102    def new(cls) -> "RequestQuoteOptions":
103        return cls()
104
105    def with_gas_sponsorship_disabled(self, disable_gas_sponsorship: bool) -> "RequestQuoteOptions":
106        self.disable_gas_sponsorship = disable_gas_sponsorship
107        return self
108
109    def with_gas_refund_address(self, gas_refund_address: str) -> "RequestQuoteOptions":
110        self.gas_refund_address = gas_refund_address
111        return self
112
113    def with_refund_native_eth(self, refund_native_eth: bool) -> "RequestQuoteOptions":
114        self.refund_native_eth = refund_native_eth
115        return self
116
117    def build_request_path(self) -> str:
118        """
119        Builds the path at which the request will be sent, with query params
120        """
121        disable_sponsorship_str = str(self.disable_gas_sponsorship).lower()
122        path = f"{REQUEST_EXTERNAL_QUOTE_ROUTE}?{DISABLE_GAS_SPONSORSHIP_QUERY_PARAM}={disable_sponsorship_str}"
123        if self.gas_refund_address:
124            path += f"&{GAS_REFUND_ADDRESS_QUERY_PARAM}={self.gas_refund_address}"
125        if self.refund_native_eth:
126            refund_native_eth_str = str(self.refund_native_eth).lower()
127            path += f"&{REFUND_NATIVE_ETH_QUERY_PARAM}={refund_native_eth_str}"
128
129        return path
RequestQuoteOptions( disable_gas_sponsorship: bool = False, gas_refund_address: Optional[str] = None, refund_native_eth: bool = False)
disable_gas_sponsorship: bool = False
gas_refund_address: Optional[str] = None
refund_native_eth: bool = False
@classmethod
def new(cls) -> RequestQuoteOptions:
101    @classmethod
102    def new(cls) -> "RequestQuoteOptions":
103        return cls()
def with_gas_sponsorship_disabled( self, disable_gas_sponsorship: bool) -> RequestQuoteOptions:
105    def with_gas_sponsorship_disabled(self, disable_gas_sponsorship: bool) -> "RequestQuoteOptions":
106        self.disable_gas_sponsorship = disable_gas_sponsorship
107        return self
def with_gas_refund_address(self, gas_refund_address: str) -> RequestQuoteOptions:
109    def with_gas_refund_address(self, gas_refund_address: str) -> "RequestQuoteOptions":
110        self.gas_refund_address = gas_refund_address
111        return self
def with_refund_native_eth(self, refund_native_eth: bool) -> RequestQuoteOptions:
113    def with_refund_native_eth(self, refund_native_eth: bool) -> "RequestQuoteOptions":
114        self.refund_native_eth = refund_native_eth
115        return self
def build_request_path(self) -> str:
117    def build_request_path(self) -> str:
118        """
119        Builds the path at which the request will be sent, with query params
120        """
121        disable_sponsorship_str = str(self.disable_gas_sponsorship).lower()
122        path = f"{REQUEST_EXTERNAL_QUOTE_ROUTE}?{DISABLE_GAS_SPONSORSHIP_QUERY_PARAM}={disable_sponsorship_str}"
123        if self.gas_refund_address:
124            path += f"&{GAS_REFUND_ADDRESS_QUERY_PARAM}={self.gas_refund_address}"
125        if self.refund_native_eth:
126            refund_native_eth_str = str(self.refund_native_eth).lower()
127            path += f"&{REFUND_NATIVE_ETH_QUERY_PARAM}={refund_native_eth_str}"
128
129        return path

Builds the path at which the request will be sent, with query params

class ExternalMatchClientError(builtins.Exception):
51class ExternalMatchClientError(Exception):
52    def __init__(self, message: str, status_code: Optional[int] = None):
53        super().__init__(message)
54        self.status_code = status_code

Common base class for all non-exit exceptions.

ExternalMatchClientError(message: str, status_code: Optional[int] = None)
52    def __init__(self, message: str, status_code: Optional[int] = None):
53        super().__init__(message)
54        self.status_code = status_code
status_code
class RelayerHttpClient:
 20class RelayerHttpClient:
 21    """HTTP client for making authenticated requests to the Renegade relayer API.
 22    
 23    This client handles request signing and authentication using HMAC-SHA256.
 24    """
 25    
 26    def __init__(self, base_url: str, auth_key: str):
 27        """Initialize a new RelayerHttpClient.
 28        
 29        Args:
 30            base_url: The base URL of the relayer API
 31            auth_key: The base64-encoded authentication key for request signing
 32        """
 33        self.async_client = AsyncClient()
 34        self.sync_client = Client()
 35        self.base_url = base_url
 36        # Decode base64 auth key
 37        self.auth_key = base64.b64decode(auth_key)
 38
 39    async def post(self, path: str, body: Any) -> Response:
 40        """Make a POST request without custom headers.
 41        
 42        Args:
 43            path: The API endpoint path
 44            body: The request body to send
 45            
 46        Returns:
 47            The API response
 48        """
 49        return await self.post_with_headers(path, body, Headers())
 50
 51    def post_sync(self, path: str, body: Any) -> Response:
 52        """Make a synchronous POST request without custom headers.
 53        
 54        Args:
 55            path: The API endpoint path
 56            body: The request body to send
 57            
 58        Returns:
 59            The API response
 60        """
 61        return self.post_with_headers_sync(path, body, Headers())
 62
 63    async def get(self, path: str) -> Response:
 64        """Make a GET request without custom headers.
 65        
 66        Args:
 67            path: The API endpoint path
 68            
 69        Returns:
 70            The API response
 71        """
 72        return await self.get_with_headers(path, Headers())
 73
 74    def get_sync(self, path: str) -> Response:
 75        """Make a synchronous GET request without custom headers.
 76        
 77        Args:
 78            path: The API endpoint path
 79            
 80        Returns:
 81            The API response
 82        """
 83        return self.get_with_headers_sync(path, Headers())
 84
 85    async def post_with_headers(self, path: str, body: Any, custom_headers: Headers) -> Response:
 86        """Make a POST request with custom headers.
 87        
 88        Args:
 89            path: The API endpoint path
 90            body: The request body to send
 91            custom_headers: Additional headers to include
 92            
 93        Returns:
 94            The API response
 95        """
 96        url = f"{self.base_url}{path}"
 97        body_bytes = json.dumps(body).encode()
 98        headers = self._add_auth(path, custom_headers, body_bytes)
 99        response = await self.async_client.post(url, headers=headers, content=body_bytes)
100        return response
101
102    def post_with_headers_sync(self, path: str, body: Any, custom_headers: Headers) -> Response:
103        """Make a synchronous POST request with custom headers.
104        
105        Args:
106            path: The API endpoint path
107            body: The request body to send
108            custom_headers: Additional headers to include
109            
110        Returns:
111            The API response
112        """
113        url = f"{self.base_url}{path}"
114        body_bytes = json.dumps(body).encode()
115        headers = self._add_auth(path, custom_headers, body_bytes)
116        response = self.sync_client.post(url, headers=headers, content=body_bytes)
117        return response
118
119    async def get_with_headers(self, path: str, custom_headers: Headers) -> Response:
120        """Make a GET request with custom headers.
121        
122        Args:
123            path: The API endpoint path
124            custom_headers: Additional headers to include
125            
126        Returns:
127            The API response
128        """
129        url = f"{self.base_url}{path}"
130        headers = self._add_auth(path, custom_headers, b"")
131        response = await self.async_client.get(url, headers=headers)
132        return response
133
134    def get_with_headers_sync(self, path: str, custom_headers: Headers) -> Response:
135        """Make a synchronous GET request with custom headers.
136        
137        Args:
138            path: The API endpoint path
139            custom_headers: Additional headers to include
140            
141        Returns:
142            The API response
143        """
144        url = f"{self.base_url}{path}"
145        headers = self._add_auth(path, custom_headers, b"")
146        response = self.sync_client.get(url, headers=headers)
147        return response
148
149    def _get_header_bytes(self, headers: Headers) -> bytes:
150        """Get sorted Renegade headers bytes for signature calculation.
151        
152        This method extracts all headers with the x-renegade prefix (except auth),
153        sorts them by key, and concatenates them into a single byte string.
154        
155        Args:
156            headers: The headers to process
157            
158        Returns:
159            A byte string containing the concatenated header data
160        """
161        renegade_headers = []
162        for key, value in headers.items():
163            key_lower = key.lower()
164            if key_lower.startswith(RENEGADE_HEADER_NAMESPACE) and key_lower != RENEGADE_AUTH_HEADER_NAME:
165                renegade_headers.append((key_lower, value))
166        
167        # Sort headers by key
168        renegade_headers.sort(key=lambda x: x[0])
169        
170        # Concatenate headers
171        header_bytes = b""
172        for key, value in renegade_headers:
173            current = key.encode() + str(value).encode()
174            header_bytes += current
175        
176        return header_bytes
177
178    def _add_auth(self, path: str, headers: Headers, body: bytes) -> Headers:
179        """Add authentication headers to a request.
180        
181        This method adds the expiration timestamp and HMAC signature headers
182        required for request authentication.
183        
184        Args:
185            path: The request path
186            headers: The existing headers
187            body: The request body bytes
188            
189        Returns:
190            Headers with authentication information added
191        """
192        # Add timestamp and expiry
193        timestamp = int(time.time() * 1000)
194        expiry = timestamp + int(REQUEST_SIGNATURE_DURATION.total_seconds() * 1000)
195        headers[RENEGADE_SIG_EXPIRATION_HEADER_NAME] = str(expiry)
196        
197        # Calculate signature
198        path_bytes = path.encode()
199        header_bytes = self._get_header_bytes(headers)
200        message = path_bytes + header_bytes + body
201
202        signature = hmac.new(self.auth_key, message, hashlib.sha256).digest()
203        b64_signature = base64.b64encode(signature).decode().rstrip("=")
204        
205        headers[RENEGADE_AUTH_HEADER_NAME] = b64_signature
206        return headers 

HTTP client for making authenticated requests to the Renegade relayer API.

This client handles request signing and authentication using HMAC-SHA256.

RelayerHttpClient(base_url: str, auth_key: str)
26    def __init__(self, base_url: str, auth_key: str):
27        """Initialize a new RelayerHttpClient.
28        
29        Args:
30            base_url: The base URL of the relayer API
31            auth_key: The base64-encoded authentication key for request signing
32        """
33        self.async_client = AsyncClient()
34        self.sync_client = Client()
35        self.base_url = base_url
36        # Decode base64 auth key
37        self.auth_key = base64.b64decode(auth_key)

Initialize a new RelayerHttpClient.

Args: base_url: The base URL of the relayer API auth_key: The base64-encoded authentication key for request signing

async_client
sync_client
base_url
auth_key
async def post(self, path: str, body: Any) -> httpx.Response:
39    async def post(self, path: str, body: Any) -> Response:
40        """Make a POST request without custom headers.
41        
42        Args:
43            path: The API endpoint path
44            body: The request body to send
45            
46        Returns:
47            The API response
48        """
49        return await self.post_with_headers(path, body, Headers())

Make a POST request without custom headers.

Args: path: The API endpoint path body: The request body to send

Returns: The API response

def post_sync(self, path: str, body: Any) -> httpx.Response:
51    def post_sync(self, path: str, body: Any) -> Response:
52        """Make a synchronous POST request without custom headers.
53        
54        Args:
55            path: The API endpoint path
56            body: The request body to send
57            
58        Returns:
59            The API response
60        """
61        return self.post_with_headers_sync(path, body, Headers())

Make a synchronous POST request without custom headers.

Args: path: The API endpoint path body: The request body to send

Returns: The API response

async def get(self, path: str) -> httpx.Response:
63    async def get(self, path: str) -> Response:
64        """Make a GET request without custom headers.
65        
66        Args:
67            path: The API endpoint path
68            
69        Returns:
70            The API response
71        """
72        return await self.get_with_headers(path, Headers())

Make a GET request without custom headers.

Args: path: The API endpoint path

Returns: The API response

def get_sync(self, path: str) -> httpx.Response:
74    def get_sync(self, path: str) -> Response:
75        """Make a synchronous GET request without custom headers.
76        
77        Args:
78            path: The API endpoint path
79            
80        Returns:
81            The API response
82        """
83        return self.get_with_headers_sync(path, Headers())

Make a synchronous GET request without custom headers.

Args: path: The API endpoint path

Returns: The API response

async def post_with_headers( self, path: str, body: Any, custom_headers: httpx.Headers) -> httpx.Response:
 85    async def post_with_headers(self, path: str, body: Any, custom_headers: Headers) -> Response:
 86        """Make a POST request with custom headers.
 87        
 88        Args:
 89            path: The API endpoint path
 90            body: The request body to send
 91            custom_headers: Additional headers to include
 92            
 93        Returns:
 94            The API response
 95        """
 96        url = f"{self.base_url}{path}"
 97        body_bytes = json.dumps(body).encode()
 98        headers = self._add_auth(path, custom_headers, body_bytes)
 99        response = await self.async_client.post(url, headers=headers, content=body_bytes)
100        return response

Make a POST request with custom headers.

Args: path: The API endpoint path body: The request body to send custom_headers: Additional headers to include

Returns: The API response

def post_with_headers_sync( self, path: str, body: Any, custom_headers: httpx.Headers) -> httpx.Response:
102    def post_with_headers_sync(self, path: str, body: Any, custom_headers: Headers) -> Response:
103        """Make a synchronous POST request with custom headers.
104        
105        Args:
106            path: The API endpoint path
107            body: The request body to send
108            custom_headers: Additional headers to include
109            
110        Returns:
111            The API response
112        """
113        url = f"{self.base_url}{path}"
114        body_bytes = json.dumps(body).encode()
115        headers = self._add_auth(path, custom_headers, body_bytes)
116        response = self.sync_client.post(url, headers=headers, content=body_bytes)
117        return response

Make a synchronous POST request with custom headers.

Args: path: The API endpoint path body: The request body to send custom_headers: Additional headers to include

Returns: The API response

async def get_with_headers(self, path: str, custom_headers: httpx.Headers) -> httpx.Response:
119    async def get_with_headers(self, path: str, custom_headers: Headers) -> Response:
120        """Make a GET request with custom headers.
121        
122        Args:
123            path: The API endpoint path
124            custom_headers: Additional headers to include
125            
126        Returns:
127            The API response
128        """
129        url = f"{self.base_url}{path}"
130        headers = self._add_auth(path, custom_headers, b"")
131        response = await self.async_client.get(url, headers=headers)
132        return response

Make a GET request with custom headers.

Args: path: The API endpoint path custom_headers: Additional headers to include

Returns: The API response

def get_with_headers_sync(self, path: str, custom_headers: httpx.Headers) -> httpx.Response:
134    def get_with_headers_sync(self, path: str, custom_headers: Headers) -> Response:
135        """Make a synchronous GET request with custom headers.
136        
137        Args:
138            path: The API endpoint path
139            custom_headers: Additional headers to include
140            
141        Returns:
142            The API response
143        """
144        url = f"{self.base_url}{path}"
145        headers = self._add_auth(path, custom_headers, b"")
146        response = self.sync_client.get(url, headers=headers)
147        return response

Make a synchronous GET request with custom headers.

Args: path: The API endpoint path custom_headers: Additional headers to include

Returns: The API response

class ExternalOrder(renegade.types.BaseModelWithConfig):
61class ExternalOrder(BaseModelWithConfig):
62    quote_mint: str
63    base_mint: str
64    side: OrderSide
65    base_amount: Optional[int] = None
66    quote_amount: Optional[int] = None
67    exact_base_output: Optional[int] = None
68    exact_quote_output: Optional[int] = None
69    min_fill_size: int = 0
70
71    def model_post_init(self, __context) -> None:
72        self.quote_mint = Web3.to_checksum_address(self.quote_mint)
73        self.base_mint = Web3.to_checksum_address(self.base_mint)
74
75    @model_validator(mode='after')
76    def validate_amounts(self) -> 'ExternalOrder':
77        # Check if all amount fields are None or 0
78        base_amt_none = self.base_amount is None or self.base_amount == 0
79        quote_amt_none = self.quote_amount is None or self.quote_amount == 0
80        exact_base_amt_none = self.exact_base_output is None or self.exact_base_output == 0
81        exact_quote_amt_none = self.exact_quote_output is None or self.exact_quote_output == 0
82        
83        # Count how many amount fields are set
84        amount_fields_set = sum(1 for x in [base_amt_none, quote_amt_none, exact_base_amt_none, exact_quote_amt_none] if not x)
85
86        if amount_fields_set == 0:
87            raise ValueError("One of base_amount, quote_amount, exact_base_amount, or exact_quote_amount must be set")
88        if amount_fields_set > 1:
89            raise ValueError("Only one of base_amount, quote_amount, exact_base_amount, or exact_quote_amount can be set")
90            
91        return self

Base model with common configuration

quote_mint: str = PydanticUndefined
base_mint: str = PydanticUndefined
side: OrderSide = PydanticUndefined
base_amount: Optional[int] = None
quote_amount: Optional[int] = None
exact_base_output: Optional[int] = None
exact_quote_output: Optional[int] = None
min_fill_size: int = 0
@model_validator(mode='after')
def validate_amounts(self) -> ExternalOrder:
75    @model_validator(mode='after')
76    def validate_amounts(self) -> 'ExternalOrder':
77        # Check if all amount fields are None or 0
78        base_amt_none = self.base_amount is None or self.base_amount == 0
79        quote_amt_none = self.quote_amount is None or self.quote_amount == 0
80        exact_base_amt_none = self.exact_base_output is None or self.exact_base_output == 0
81        exact_quote_amt_none = self.exact_quote_output is None or self.exact_quote_output == 0
82        
83        # Count how many amount fields are set
84        amount_fields_set = sum(1 for x in [base_amt_none, quote_amt_none, exact_base_amt_none, exact_quote_amt_none] if not x)
85
86        if amount_fields_set == 0:
87            raise ValueError("One of base_amount, quote_amount, exact_base_amount, or exact_quote_amount must be set")
88        if amount_fields_set > 1:
89            raise ValueError("Only one of base_amount, quote_amount, exact_base_amount, or exact_quote_amount can be set")
90            
91        return self
class OrderSide(builtins.str, enum.Enum):
 9class OrderSide(str, Enum):
10    BUY = "Buy"
11    SELL = "Sell"

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to 'utf-8'. errors defaults to 'strict'.

BUY = <OrderSide.BUY: 'Buy'>
SELL = <OrderSide.SELL: 'Sell'>