Skip to main content

blokli_client/
errors.rs

1use cynic::http::CynicReqwestError;
2
3/// Error type for the Blokli client.
4///
5/// Most public methods return this type for transport failures, GraphQL errors, Blokli application errors, parsing
6/// failures, invalid local inputs, and transaction tracking failures. Use [`BlokliClientError::kind`] to inspect the
7/// stable [`ErrorKind`] category.
8#[derive(Debug)]
9pub struct BlokliClientError(Box<ErrorKind>);
10
11impl BlokliClientError {
12    /// Returns the reference to [`ErrorKind`].
13    pub fn kind(&self) -> &ErrorKind {
14        self.0.as_ref()
15    }
16}
17
18impl<T: Into<ErrorKind>> From<T> for BlokliClientError {
19    fn from(kind: T) -> Self {
20        Self(Box::new(kind.into()))
21    }
22}
23
24impl std::fmt::Display for BlokliClientError {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        self.0.fmt(f)
27    }
28}
29
30impl std::error::Error for BlokliClientError {
31    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
32        Some(self.0.as_ref())
33    }
34}
35
36/// Error kinds for transaction tracking failure.
37#[derive(Copy, Clone, Debug, PartialEq, Eq)]
38pub enum TrackingErrorKind {
39    /// Transaction was reverted.
40    Reverted,
41    /// Transaction timed out in Blokli.
42    Timeout,
43    /// Transaction submission failed.
44    SubmissionFailed,
45    /// Transaction validation failed.
46    ValidationFailed,
47}
48
49/// Error kinds for the Blokli client.
50#[derive(Debug, thiserror::Error)]
51pub enum ErrorKind {
52    /// Blokli returned neither data nor usable GraphQL errors.
53    #[error("no data returned from blokli unexpectedly")]
54    NoData,
55    /// Blokli returned an application-level error through a GraphQL union result.
56    #[error("remote blokli error: {kind} ({code}): {message}")]
57    BlokliError {
58        /// Error family assigned by the client conversion layer.
59        kind: &'static str,
60        /// Stable error code returned by Blokli.
61        code: String,
62        /// Human-readable error message returned by Blokli.
63        message: String,
64    },
65    /// Local input was rejected before the request was sent.
66    #[error("invalid query input: {0}")]
67    InvalidInput(&'static str),
68    /// Transaction tracking reached a terminal failure state.
69    #[error("transaction tracking error: {0:?}")]
70    TrackingError(TrackingErrorKind),
71    /// Blokli returned data in a shape or encoding the client could not parse.
72    #[error("data returned from blokli was unparseable")]
73    ParseError,
74    /// A client-side timeout elapsed.
75    #[error("operation timed out at the client")]
76    Timeout,
77    /// SSE subscription setup or transport failed.
78    #[error(transparent)]
79    Subscription(#[from] Box<eventsource_client::Error>),
80    /// A URL could not be parsed or derived.
81    #[error(transparent)]
82    UrlParse(#[from] url::ParseError),
83    /// JSON serialization or deserialization failed.
84    #[error(transparent)]
85    Serialization(#[from] serde_json::Error),
86    /// HTTP transport failed.
87    #[error(transparent)]
88    Reqwest(#[from] reqwest::Error),
89    /// Cynic request/response handling failed.
90    #[error(transparent)]
91    Cynic(#[from] CynicReqwestError),
92    /// GraphQL returned errors without usable data.
93    #[error(transparent)]
94    GraphQLError(#[from] cynic::GraphQlError),
95    #[cfg(feature = "testing")]
96    #[error(transparent)]
97    MockClientError(#[from] anyhow::Error),
98}
99
100/// A special kind of error type that is used to wrap errors simulates internal Safe TX failures.
101#[cfg(feature = "testing")]
102#[derive(Debug)]
103pub struct InternalTxError(pub anyhow::Error);
104
105#[cfg(feature = "testing")]
106impl std::fmt::Display for InternalTxError {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        write!(f, "internal TX error: {}", self.0)
109    }
110}
111
112#[cfg(feature = "testing")]
113impl std::error::Error for InternalTxError {}