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 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 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;