diff --git a/src/polymarket/_internal/rfq.py b/src/polymarket/_internal/rfq.py index 21382f3..b655880 100644 --- a/src/polymarket/_internal/rfq.py +++ b/src/polymarket/_internal/rfq.py @@ -451,6 +451,9 @@ def _handle_rfq_error(self, raw: dict[str, object]) -> None: request_type = raw.get("request_type") rfq_id = raw.get("rfq_id") quote_id = raw.get("quote_id") + error_id = raw.get("error_id") + if error_id is not None and not isinstance(error_id, str): + raise UnexpectedResponseError("Expected RFQ error_id to be a string.") code = _parse_error_code(raw.get("code")) message = raw.get("error") text = message if isinstance(message, str) else "RFQ request failed." @@ -459,7 +462,7 @@ def _handle_rfq_error(self, raw: dict[str, object]) -> None: raise TransportError("Uncorrelated RFQ quoter error.") self._reject( _quote_ack_key(rfq_id), - RfqQuoteRejectedError(text, rfq_id=rfq_id, code=code), + RfqQuoteRejectedError(text, rfq_id=rfq_id, code=code, error_id=error_id), ) elif request_type == "RFQ_QUOTE_CANCEL": if not isinstance(rfq_id, str) or not isinstance(quote_id, str): @@ -471,6 +474,7 @@ def _handle_rfq_error(self, raw: dict[str, object]) -> None: rfq_id=rfq_id, quote_id=quote_id, code=code, + error_id=error_id, ), ) elif request_type == "RFQ_CONFIRMATION_RESPONSE": @@ -483,6 +487,7 @@ def _handle_rfq_error(self, raw: dict[str, object]) -> None: rfq_id=rfq_id, quote_id=quote_id, code=code, + error_id=error_id, ), ) diff --git a/src/polymarket/rfq.py b/src/polymarket/rfq.py index d94118c..a8d855d 100644 --- a/src/polymarket/rfq.py +++ b/src/polymarket/rfq.py @@ -63,6 +63,8 @@ class RfqErrorCode(StrEnum): INVALID_RFQ = "INVALID_RFQ" INVALID_RFQ_STATE = "INVALID_RFQ_STATE" INVALID_ROLE = "INVALID_ROLE" + INVALID_SIGNATURE = "INVALID_SIGNATURE" + INTERNAL_ERROR = "INTERNAL_ERROR" LEG_METADATA_UNAVAILABLE = "LEG_METADATA_UNAVAILABLE" MAKER_ALREADY_RESPONDED = "MAKER_ALREADY_RESPONDED" MAKER_NOT_REQUIRED = "MAKER_NOT_REQUIRED" @@ -170,10 +172,18 @@ async def decline(self) -> RfqConfirmationAck: class RfqQuoteRejectedError(PolymarketError): - def __init__(self, message: str, *, rfq_id: RfqId, code: RfqErrorCode | None = None) -> None: + def __init__( + self, + message: str, + *, + rfq_id: RfqId, + code: RfqErrorCode | None = None, + error_id: str | None = None, + ) -> None: super().__init__(message) self.rfq_id = rfq_id self.code = code + self.error_id = error_id class RfqCancelQuoteRejectedError(PolymarketError): @@ -184,11 +194,13 @@ def __init__( rfq_id: RfqId, quote_id: RfqQuoteId, code: RfqErrorCode | None = None, + error_id: str | None = None, ) -> None: super().__init__(message) self.rfq_id = rfq_id self.quote_id = quote_id self.code = code + self.error_id = error_id class RfqConfirmationRejectedError(PolymarketError): @@ -199,11 +211,13 @@ def __init__( rfq_id: RfqId, quote_id: RfqQuoteId, code: RfqErrorCode | None = None, + error_id: str | None = None, ) -> None: super().__init__(message) self.rfq_id = rfq_id self.quote_id = quote_id self.code = code + self.error_id = error_id @runtime_checkable diff --git a/tests/integration/test_rfq.py b/tests/integration/test_rfq.py index 02af98d..0a9686c 100644 --- a/tests/integration/test_rfq.py +++ b/tests/integration/test_rfq.py @@ -389,6 +389,7 @@ async def handler(ws: ServerConnection) -> None: { "type": "RFQ_ERROR", "request_type": "RFQ_QUOTE", + "error_id": "reqerr-1", "rfq_id": RFQ_ID, "code": code, "error": "quote rejected", @@ -406,6 +407,7 @@ async def handler(ws: ServerConnection) -> None: with pytest.raises(RfqQuoteRejectedError, match="quote rejected") as exc_info: await event.quote(price=Decimal("0.45")) assert exc_info.value.code == code + assert exc_info.value.error_id == "reqerr-1" break