near_api/
errors.rs

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