Skip to main content

leptos_solana/
error.rs

1use thiserror::Error;
2
3pub type Result<T> = core::result::Result<T, Error>;
4
5#[derive(Debug, Error)]
6pub enum Error {
7    #[error("wallet standard not available on this page (navigator.wallets missing)")]
8    WalletsUnavailable,
9
10    #[error("wallet does not expose feature `{0}`")]
11    MissingFeature(&'static str),
12
13    #[error("wallet has no connected account")]
14    NoAccount,
15
16    #[error("wallet does not support chain `{0}`")]
17    UnsupportedChain(String),
18
19    #[error("user rejected the request")]
20    UserRejected,
21
22    #[error("js interop: {0}")]
23    Js(String),
24
25    #[error("decode: {0}")]
26    Decode(String),
27
28    #[error("rpc: {0}")]
29    Rpc(String),
30
31    #[error("serialize: {0}")]
32    Serialize(String),
33}
34
35impl From<wasm_bindgen::JsValue> for Error {
36    fn from(v: wasm_bindgen::JsValue) -> Self {
37        // Wallets conventionally throw `{ code: 4001, message: "User rejected" }`.
38        if let Some(obj) = v.dyn_ref::<js_sys::Object>() {
39            if let Ok(code) = js_sys::Reflect::get(obj, &"code".into()) {
40                if code.as_f64() == Some(4001.0) {
41                    return Error::UserRejected;
42                }
43            }
44        }
45
46        // JS Error objects don't expose `message` as enumerable, so
47        // `JSON.stringify(err)` yields `{}`. Pull the real fields via Reflect.
48        if let Some(obj) = v.dyn_ref::<js_sys::Object>() {
49            let msg = js_sys::Reflect::get(obj, &"message".into())
50                .ok()
51                .and_then(|m| m.as_string())
52                .filter(|s| !s.is_empty());
53            let name = js_sys::Reflect::get(obj, &"name".into())
54                .ok()
55                .and_then(|n| n.as_string())
56                .filter(|s| !s.is_empty());
57            let code = js_sys::Reflect::get(obj, &"code".into())
58                .ok()
59                .and_then(|c| c.as_f64());
60
61            if msg.is_some() || name.is_some() || code.is_some() {
62                let mut s = String::new();
63                if let Some(n) = name {
64                    s.push_str(&n);
65                }
66                if let Some(c) = code {
67                    if !s.is_empty() {
68                        s.push(' ');
69                    }
70                    s.push_str(&format!("({c:.0})"));
71                }
72                if let Some(m) = msg {
73                    if !s.is_empty() {
74                        s.push_str(": ");
75                    }
76                    s.push_str(&m);
77                }
78                return Error::Js(s);
79            }
80        }
81
82        Error::Js(
83            v.as_string()
84                .or_else(|| js_sys::JSON::stringify(&v).ok().and_then(|s| s.as_string()))
85                .unwrap_or_else(|| "unknown js error".into()),
86        )
87    }
88}
89
90use wasm_bindgen::JsCast;