anvil_rpc/
error.rs

1//! JSON-RPC error bindings
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::{borrow::Cow, fmt};
4
5/// Represents a JSON-RPC error
6#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(deny_unknown_fields)]
8pub struct RpcError {
9    pub code: ErrorCode,
10    /// error message
11    pub message: Cow<'static, str>,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub data: Option<serde_json::Value>,
14}
15
16impl RpcError {
17    /// New [`RpcError`] with the given [`ErrorCode`].
18    pub const fn new(code: ErrorCode) -> Self {
19        Self { message: Cow::Borrowed(code.message()), code, data: None }
20    }
21
22    /// Creates a new `ParseError` error.
23    pub const fn parse_error() -> Self {
24        Self::new(ErrorCode::ParseError)
25    }
26
27    /// Creates a new `MethodNotFound` error.
28    pub const fn method_not_found() -> Self {
29        Self::new(ErrorCode::MethodNotFound)
30    }
31
32    /// Creates a new `InvalidRequest` error.
33    pub const fn invalid_request() -> Self {
34        Self::new(ErrorCode::InvalidRequest)
35    }
36
37    /// Creates a new `InternalError` error.
38    pub const fn internal_error() -> Self {
39        Self::new(ErrorCode::InternalError)
40    }
41
42    /// Creates a new `InvalidParams` error.
43    pub fn invalid_params<M>(message: M) -> Self
44    where
45        M: Into<String>,
46    {
47        Self { code: ErrorCode::InvalidParams, message: message.into().into(), data: None }
48    }
49
50    /// Creates a new `InternalError` error with a message.
51    pub fn internal_error_with<M>(message: M) -> Self
52    where
53        M: Into<String>,
54    {
55        Self { code: ErrorCode::InternalError, message: message.into().into(), data: None }
56    }
57
58    /// Creates a new RPC error for when a transaction was rejected.
59    pub fn transaction_rejected<M>(message: M) -> Self
60    where
61        M: Into<String>,
62    {
63        Self { code: ErrorCode::TransactionRejected, message: message.into().into(), data: None }
64    }
65}
66
67impl fmt::Display for RpcError {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(f, "{}: {}", self.code.message(), self.message)
70    }
71}
72
73/// List of JSON-RPC error codes
74#[derive(Clone, Copy, Debug, PartialEq, Eq)]
75pub enum ErrorCode {
76    /// Server received Invalid JSON.
77    /// server side error while parsing JSON
78    ParseError,
79    /// send invalid request object.
80    InvalidRequest,
81    /// method does not exist or valid
82    MethodNotFound,
83    /// invalid method parameter.
84    InvalidParams,
85    /// internal call error
86    InternalError,
87    /// Failed to send transaction, See also <https://github.com/MetaMask/eth-rpc-errors/blob/main/src/error-constants.ts>
88    TransactionRejected,
89    /// Custom geth error code, <https://github.com/vapory-legacy/wiki/blob/master/JSON-RPC-Error-Codes-Improvement-Proposal.md>
90    ExecutionError,
91    /// Used for server specific errors.
92    ServerError(i64),
93}
94
95impl ErrorCode {
96    /// Returns the error code as `i64`
97    pub fn code(&self) -> i64 {
98        match *self {
99            Self::ParseError => -32700,
100            Self::InvalidRequest => -32600,
101            Self::MethodNotFound => -32601,
102            Self::InvalidParams => -32602,
103            Self::InternalError => -32603,
104            Self::TransactionRejected => -32003,
105            Self::ExecutionError => 3,
106            Self::ServerError(c) => c,
107        }
108    }
109
110    /// Returns the message associated with the error
111    pub const fn message(&self) -> &'static str {
112        match *self {
113            Self::ParseError => "Parse error",
114            Self::InvalidRequest => "Invalid request",
115            Self::MethodNotFound => "Method not found",
116            Self::InvalidParams => "Invalid params",
117            Self::InternalError => "Internal error",
118            Self::TransactionRejected => "Transaction rejected",
119            Self::ServerError(_) => "Server error",
120            Self::ExecutionError => "Execution error",
121        }
122    }
123}
124
125impl Serialize for ErrorCode {
126    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
127    where
128        S: Serializer,
129    {
130        serializer.serialize_i64(self.code())
131    }
132}
133
134impl<'a> Deserialize<'a> for ErrorCode {
135    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
136    where
137        D: Deserializer<'a>,
138    {
139        i64::deserialize(deserializer).map(Into::into)
140    }
141}
142
143impl From<i64> for ErrorCode {
144    fn from(code: i64) -> Self {
145        match code {
146            -32700 => Self::ParseError,
147            -32600 => Self::InvalidRequest,
148            -32601 => Self::MethodNotFound,
149            -32602 => Self::InvalidParams,
150            -32603 => Self::InternalError,
151            -32003 => Self::TransactionRejected,
152            3 => Self::ExecutionError,
153            _ => Self::ServerError(code),
154        }
155    }
156}