1use thiserror::Error;
2use web_sys::js_sys::{wasm_bindgen::JsValue, Reflect};
3
4use crate::WalletEvent;
5
6pub type WalletResult<T> = Result<T, WalletError>;
8
9impl From<async_channel::SendError<WalletEvent>> for WalletError {
10 fn from(value: async_channel::SendError<WalletEvent>) -> Self {
11 match value {
12 async_channel::SendError(_) => Self::ChannelError,
13 }
14 }
15}
16
17#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Error)]
19pub enum WalletError {
20 #[error("Unable to send the a `WalletEvent` variant via the WalletEventSender channel")]
22 ChannelError,
23 #[error("{message}")]
29 JsError {
30 name: String,
32 message: String,
34 stack: String,
36 },
37 #[error("Internal Error `{0}` occurred, this is a bug in the library please open an issue at https://github.com/JamiiDao/SolanaWalletAdapter/issues")]
43 InternalError(String),
44 #[error("A value of `undefined` or `null` was encountered")]
46 ValueNotFound,
47 #[error("A value of `{0}` was expected but it does not exist in the `JsValue`")]
49 ExpectedValueNotFound(String),
50 #[error("Unable to access browser window")]
52 MissingAccessToBrowserWindow,
53 #[error("Unable to access browser document")]
55 MissingAccessToBrowserDocument,
56 #[error("Unsupported Commitment level `{0}`. Only `processed`, `confirmed` and `finalized` commitments are supported by Solana clusters")]
58 UnsupportedCommitment(String),
59 #[error("The wallet version `{0}` is invalid, expected SemVer version")]
61 InvalidWalletVersion(String),
62 #[error("Unexpected SemVer number `{0}` to parse to a `u8`")]
64 InvalidSemVerNumber(String),
65 #[error("The byte length should be equal to 32 bytes in length")]
67 Expected32ByteLength,
68 #[error("The byte length should be equal to 64 bytes in length")]
70 Expected64ByteLength,
71 #[error("The version was not found")]
73 VersionNotFound,
74 #[error("The feature `{0}` is not supported as a standard or solana namespace feature")]
76 UnsupportedWalletFeature(String),
77 #[error("Encountered an unsupported transaction version. Only `legacy` and `version zero` transactions are supported.")]
80 UnsupportedTransactionVersion,
81 #[error("Legacy transaction versions need to be supported yet the encountered wallet does not do this.")]
83 LegacyTransactionSupportRequired,
84 #[error("The blockchain `{0}` is not supported")]
86 UnsupportedChain(String),
87 #[error("The `connect` function of the `standard:connect` namespace was not found while parsing a wallet")]
89 MissingConnectFunction,
90 #[error("Attempted to connect to a wallet that does not exist or is yet to be registered")]
92 WalletNotFound,
93 #[error(
95 "Attempted to connect to an account that does not exist or might have been disconnected"
96 )]
97 AccountNotFound,
98 #[error("Unable to connect to a wallet. Error `{0}` request")]
100 WalletConnectError(String),
101 #[error("The connect method did not return any accounts")]
103 ConnectHasNoAccounts,
104 #[error("The wallet `standard:disconnect` feature is missing")]
106 MissingDisconnectFunction,
107 #[error("The `accounts` method to get the accounts connected to a wallet is missing from wallet `{0}`")]
109 MissingGetAccountsFunction(String),
110 #[error("Wallet Disconnect error - `{0}`")]
112 WalletDisconnectError(String),
113 #[error("Encountered `standard:events` error `{0}`")]
115 StandardEventsError(String),
116 #[error("Called The Function for `standard:events` yet the wallet does not provide it")]
118 MissingStandardEventsFunction,
119 #[error("The wallet did not register a signIn function for `solana:signIn` namespece")]
121 MissingSignInFunction,
122 #[error("This token expires earlier than it was issued. Make sure to set the expiry time to be a later date than the issued time")]
124 ExpiryTimeEarlierThanIssuedTime,
125 #[error("This token becomes valid earlier than it was issued. Make sure to set the not_before time to be equal to or a later date than the issued time")]
127 NotBeforeTimeEarlierThanIssuedTime,
128 #[error("This token becomes valid after it has already expired. Make sure to set the not_before time to be equal to or a date before expiry time")]
130 NotBeforeTimeLaterThanExpirationTime,
131 #[error("The expiration time is set to expire in the past")]
133 ExpirationTimeIsInThePast,
134 #[error("NotBefore time is set in the past")]
136 NotBeforeTimeIsInThePast,
137 #[error("Invalid Base58 Address")]
139 InvalidBase58Address,
140 #[error("The nonce is required to be at least 8 characters long")]
142 NonceMustBeAtLeast8Characters,
143 #[error("Invalid ISO 8601 timestamp `{0}. Only timestamps in the format specified by ISO8601 are supported.")]
145 InvalidISO8601Timestamp(String),
146 #[error("The message signed by the wallet is not the same as the message sent to the wallet for signing")]
148 MessageResponseMismatch,
149 #[error("The Ed25519 Signature is invalid for the signed message and public key")]
151 InvalidSignature,
152 #[error("The bytes provided for the Ed25519 Signature are invalid")]
154 InvalidEd25519SignatureBytes,
155 #[error("The bytes provided for the Ed25519 Public Key are invalid")]
157 InvalidEd25519PublicKeyBytes,
158 #[error("The function call to Sign A Message Is Missing")]
160 MissingSignMessageFunction,
161 #[error("The message sent to the wallet to be signed is different from the message the wallet responded with")]
163 SignedMessageMismatch,
164 #[error("The Wallet returned an empty array of signed messages")]
166 ReceivedAnEmptySignedMessagesArray,
167 #[error("The `solana:signTransaction` function is missing in the provided wallet")]
169 MissingSignTransactionFunction,
170 #[error("The `sendAndSignTransaction` method did not return any signature")]
172 SendAndSignTransactionSignatureEmpty,
173 #[error("An operation resulted in an error `{0}`.")]
178 Op(String),
179}
180
181impl From<JsValue> for WalletError {
182 fn from(value: JsValue) -> Self {
183 let reflect = |key: &str| -> Result<String, Self> {
184 Reflect::get(&value, &key.into())
185 .map_err(|error: JsValue| WalletError::InternalError(format!("{:?}", &error)))?
186 .as_string()
187 .ok_or(WalletError::InternalError(format!(
188 "Reflecting `{key}` in `{value:?}` did not yield a JsString"
189 )))
190 };
191
192 let name = match reflect("name") {
193 Ok(inner) => inner,
194 Err(error) => return error,
195 };
196
197 let stack = match reflect("stack") {
198 Ok(inner) => inner,
199 Err(error) => return error,
200 };
201 let message = match reflect("message") {
202 Ok(inner) => inner,
203 Err(error) => return error,
204 };
205
206 Self::JsError {
207 message,
208 name,
209 stack,
210 }
211 }
212}