near_api/
errors.rs

1use std::sync::Arc;
2
3use near_api_types::errors::DataConversionError;
4use near_openapi_client::types::{
5    FunctionCallError, InternalError, RpcQueryError, RpcRequestValidationErrorKind,
6    RpcTransactionError,
7};
8
9#[derive(thiserror::Error, Debug)]
10pub enum QueryCreationError {
11    #[error("Staking pool factory account ID is not defined in the network config")]
12    StakingPoolFactoryNotDefined,
13}
14
15#[derive(thiserror::Error, Debug)]
16pub enum QueryError<RpcError: std::fmt::Debug + Send + Sync> {
17    #[error(transparent)]
18    QueryCreationError(#[from] QueryCreationError),
19    #[error("Unexpected response kind: expected {expected} type, but got {got:?}")]
20    UnexpectedResponse {
21        expected: &'static str,
22        // Boxed to avoid large error type
23        got: &'static str,
24    },
25    #[error("Failed to deserialize response: {0}")]
26    DeserializeError(#[from] serde_json::Error),
27    #[error("Query error: {0:?}")]
28    QueryError(Box<RetryError<SendRequestError<RpcError>>>),
29    #[error("Internal error: failed to get response. Please submit a bug ticket")]
30    InternalErrorNoResponse,
31    #[error("Argument serialization error: {0}")]
32    ArgumentValidationError(#[from] ArgumentValidationError),
33    #[error("Failed to convert response: {0}")]
34    ConversionError(Box<dyn std::error::Error + Send + Sync>),
35}
36
37impl<RpcError: std::fmt::Debug + Send + Sync> From<RetryError<SendRequestError<RpcError>>>
38    for QueryError<RpcError>
39{
40    fn from(err: RetryError<SendRequestError<RpcError>>) -> Self {
41        Self::QueryError(Box::new(err))
42    }
43}
44
45#[derive(thiserror::Error, Debug)]
46pub enum MetaSignError {
47    #[error("Attempted to construct NonDelegateAction from Action::Delegate")]
48    DelegateActionIsNotSupported,
49
50    #[error(transparent)]
51    SignerError(#[from] SignerError),
52}
53
54#[derive(thiserror::Error, Debug)]
55pub enum PublicKeyError {
56    #[error("Public key is not available")]
57    PublicKeyIsNotAvailable,
58    #[cfg(feature = "ledger")]
59    #[error("Failed to cache public key: {0}")]
60    SetPublicKeyError(#[from] tokio::sync::SetError<crate::PublicKey>),
61}
62
63#[derive(thiserror::Error, Debug)]
64pub enum SignerError {
65    #[error(transparent)]
66    PublicKeyError(#[from] PublicKeyError),
67    #[error("Secret key is not available")]
68    SecretKeyIsNotAvailable,
69    #[error("Failed to fetch nonce: {0:?}")]
70    FetchNonceError(Box<QueryError<RpcQueryError>>),
71    #[error("IO error: {0}")]
72    IO(#[from] std::io::Error),
73
74    #[cfg(feature = "ledger")]
75    #[error(transparent)]
76    LedgerError(#[from] LedgerError),
77}
78
79#[derive(thiserror::Error, Debug)]
80pub enum SecretError {
81    #[error("Failed to process seed phrase: {0}")]
82    BIP39Error(#[from] bip39::Error),
83    #[error("Failed to derive key from seed phrase: Invalid Index")]
84    DeriveKeyInvalidIndex,
85    #[error(transparent)]
86    PublicKeyError(#[from] PublicKeyError),
87}
88
89#[derive(thiserror::Error, Debug)]
90pub enum AccessKeyFileError {
91    #[error("Failed to read access key file: {0}")]
92    ReadError(#[from] std::io::Error),
93    #[error("Failed to parse access key file: {0}")]
94    ParseError(#[from] serde_json::Error),
95    #[error(transparent)]
96    SecretError(#[from] SecretError),
97    #[error("Public key is not linked to the private key")]
98    PrivatePublicKeyMismatch,
99    #[error(transparent)]
100    PublicKeyError(#[from] PublicKeyError),
101}
102
103#[cfg(feature = "keystore")]
104#[derive(thiserror::Error, Debug)]
105pub enum KeyStoreError {
106    #[error(transparent)]
107    Keystore(#[from] keyring::Error),
108    #[error("Failed to query account keys: {0:?}")]
109    QueryError(QueryError<RpcQueryError>),
110    #[error("Failed to parse access key file: {0}")]
111    ParseError(#[from] serde_json::Error),
112    #[error(transparent)]
113    SecretError(#[from] SecretError),
114    #[error("Task execution error: {0}")]
115    TaskExecutionError(#[from] tokio::task::JoinError),
116}
117
118#[cfg(feature = "ledger")]
119#[derive(thiserror::Error, Debug)]
120pub enum LedgerError {
121    #[error(
122        "Buffer overflow on Ledger device occurred. \
123Transaction is too large for signature. \
124This is resolved in https://github.com/dj8yfo/app-near-rs . \
125The status is tracked in `About` section."
126    )]
127    BufferOverflow,
128    #[error("Ledger device error: {0:?}")]
129    LedgerError(near_ledger::NEARLedgerError),
130    #[error("IO error: {0}")]
131    IO(#[from] std::io::Error),
132    #[error("Task execution error: {0}")]
133    TaskExecutionError(#[from] tokio::task::JoinError),
134    #[error("Signature is not expected to fail on deserialization: {0}")]
135    SignatureDeserializationError(String),
136}
137
138#[cfg(feature = "ledger")]
139impl From<near_ledger::NEARLedgerError> for LedgerError {
140    fn from(err: near_ledger::NEARLedgerError) -> Self {
141        const SW_BUFFER_OVERFLOW: &str = "0x6990";
142
143        match err {
144            near_ledger::NEARLedgerError::APDUExchangeError(msg)
145                if msg.contains(SW_BUFFER_OVERFLOW) =>
146            {
147                Self::BufferOverflow
148            }
149            near_ledger_error => Self::LedgerError(near_ledger_error),
150        }
151    }
152}
153
154#[derive(thiserror::Error, Debug, Clone)]
155pub enum ArgumentValidationError {
156    #[error("Failed to serialize arguments as JSON: {0}")]
157    JsonSerializationError(Arc<serde_json::Error>),
158    #[error("Failed to serialize arguments as Borsh: {0}")]
159    BorshSerializationError(Arc<std::io::Error>),
160    #[error("Account creation error: {0}")]
161    AccountCreationError(#[from] AccountCreationError),
162    #[error("Multiple errors: {0:?}")]
163    MultipleErrors(Vec<ArgumentValidationError>),
164}
165
166impl ArgumentValidationError {
167    pub const fn multiple(errors: Vec<Self>) -> Self {
168        Self::MultipleErrors(errors)
169    }
170}
171
172impl From<serde_json::Error> for ArgumentValidationError {
173    fn from(err: serde_json::Error) -> Self {
174        Self::JsonSerializationError(Arc::new(err))
175    }
176}
177
178impl From<std::io::Error> for ArgumentValidationError {
179    fn from(err: std::io::Error) -> Self {
180        Self::BorshSerializationError(Arc::new(err))
181    }
182}
183
184#[derive(thiserror::Error, Debug, Clone)]
185pub enum AccountCreationError {
186    #[error("Top-level account is not allowed")]
187    TopLevelAccountIsNotAllowed,
188
189    #[error("Linkdrop is not defined in the network config")]
190    LinkdropIsNotDefined,
191
192    #[error("Account should be created as a sub-account of the signer or linkdrop account")]
193    AccountShouldBeSubAccountOfSignerOrLinkdrop,
194}
195
196#[derive(thiserror::Error, Debug)]
197pub enum FaucetError {
198    #[error(
199        "The <{0}> network config does not have a defined faucet (helper service) that can sponsor the creation of an account."
200    )]
201    FaucetIsNotDefined(String),
202    #[error("Failed to send message: {0}")]
203    SendError(#[from] reqwest::Error),
204}
205
206#[derive(thiserror::Error, Debug)]
207pub enum RetryError<E> {
208    #[error("No RPC endpoints are defined in the network config")]
209    NoRpcEndpoints,
210    #[error("Invalid API key: {0}")]
211    InvalidApiKey(#[from] reqwest::header::InvalidHeaderValue),
212    #[error("Request failed. Retries exhausted. Last error: {0}")]
213    RetriesExhausted(E),
214    #[error("Critical error: {0}")]
215    Critical(E),
216}
217
218#[derive(thiserror::Error, Debug)]
219pub enum ExecuteTransactionError {
220    #[error(transparent)]
221    ArgumentValidationError(#[from] ArgumentValidationError),
222
223    #[error("Pre-query error: {0:?}")]
224    PreQueryError(QueryError<RpcQueryError>),
225    #[error("Transaction validation error: {0}")]
226    ValidationError(#[from] ValidationError),
227    #[error("Meta-signing error: {0}")]
228    MetaSignError(#[from] MetaSignError),
229    #[error("Transaction signing error: {0}")]
230    SignerError(#[from] SignerError),
231
232    #[error("Transaction error: {0:?}")]
233    TransactionError(RetryError<SendRequestError<RpcTransactionError>>),
234    #[error("Data conversion error: {0}")]
235    DataConversionError(#[from] DataConversionError),
236}
237
238#[derive(thiserror::Error, Debug)]
239pub enum ExecuteMetaTransactionsError {
240    #[error(transparent)]
241    ArgumentValidationError(#[from] ArgumentValidationError),
242
243    #[error("Pre-query error: {0:?}")]
244    PreQueryError(QueryError<RpcQueryError>),
245    #[error("Transaction validation error: {0}")]
246    ValidationError(#[from] ValidationError),
247    #[error("Relayer is not defined in the network config")]
248    RelayerIsNotDefined,
249
250    #[error("Meta-signing error: {0}")]
251    SignError(#[from] MetaSignError),
252
253    #[error("Failed to send meta-transaction: {0}")]
254    SendError(#[from] reqwest::Error),
255}
256
257#[derive(thiserror::Error, Debug)]
258pub enum FTValidatorError {
259    #[deprecated(
260        since = "0.7.3",
261        note = "this error is unused as we are not falling if no metadata provided"
262    )]
263    #[error("Metadata is not provided")]
264    NoMetadata,
265    #[error("Decimals mismatch: expected {expected}, got {got}")]
266    DecimalsMismatch { expected: u8, got: u8 },
267    #[error("Storage deposit is needed")]
268    StorageDepositNeeded,
269}
270
271//TODO: it's better to have a separate errors, but for now it would be aggregated here
272#[derive(thiserror::Error, Debug)]
273pub enum ValidationError {
274    #[error("Query error: {0:?}")]
275    QueryError(QueryError<RpcQueryError>),
276
277    #[error(transparent)]
278    ArgumentValidationError(#[from] ArgumentValidationError),
279
280    #[error("FT Validation Error: {0}")]
281    FTValidatorError(#[from] FTValidatorError),
282
283    #[error("Account creation error: {0}")]
284    AccountCreationError(#[from] AccountCreationError),
285}
286
287#[derive(thiserror::Error, Debug)]
288pub enum SendRequestError<RpcError: std::fmt::Debug + Send + Sync> {
289    #[error("Query creation error: {0}")]
290    RequestCreationError(#[from] QueryCreationError),
291    #[error("Transport error: {0}")]
292    TransportError(near_openapi_client::Error<()>),
293    // This is a hack to support the old error handling in the RPC API.
294    #[error("Wasm execution failed with error: {0}")]
295    WasmExecutionError(#[from] FunctionCallError),
296    #[error("Internal error: {0:?}")]
297    InternalError(#[from] InternalError),
298    #[error("Request validation error: {0:?}")]
299    RequestValidationError(#[from] RpcRequestValidationErrorKind),
300    #[error("Server error: {0}")]
301    ServerError(RpcError),
302}
303
304// That's a BIG BIG HACK to handle inconsistent RPC errors
305//
306// Node responds as a message instead of an error object, so we need to parse the message and return the error.
307// https://github.com/near/nearcore/blob/ae6fd841eaad76a090a02e9dcf7406bc79b81dbb/chain/jsonrpc/src/lib.rs#L204
308//
309// TODO: remove this once we have a proper error handling in the RPC API.
310// - https://github.com/near/near-sdk-rs/pull/1165
311// - nearcore PR
312impl<RpcError: std::fmt::Debug + Send + Sync> From<near_openapi_client::Error<()>>
313    for SendRequestError<RpcError>
314{
315    fn from(err: near_openapi_client::Error<()>) -> Self {
316        if let near_openapi_client::Error::InvalidResponsePayload(bytes, _error) = &err {
317            let error = serde_json::from_slice::<serde_json::Value>(bytes)
318                .unwrap_or_default()
319                .get("result")
320                .and_then(|result| result.get("error"))
321                .and_then(|message| message.as_str())
322                .and_then(|message| message.strip_prefix("wasm execution failed with error: "))
323                .and_then(|message| serde_dbgfmt::from_str::<FunctionCallError>(message).ok());
324            if let Some(error) = error {
325                return Self::WasmExecutionError(error);
326            }
327        }
328
329        Self::TransportError(err)
330    }
331}