1use thiserror::Error;
2use wallet_adapter_common::WalletUtilsError;
3use web_sys::js_sys::{wasm_bindgen::JsValue, Reflect};
4
5use crate::WalletEvent;
6
7pub type WalletResult<T> = Result<T, WalletError>;
9
10impl From<async_channel::SendError<WalletEvent>> for WalletError {
11 fn from(value: async_channel::SendError<WalletEvent>) -> Self {
12 match value {
13 async_channel::SendError(_) => Self::ChannelError,
14 }
15 }
16}
17
18#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Error)]
20pub enum WalletError {
21 #[error("Unable to send the a `WalletEvent` variant via the WalletEventSender channel")]
23 ChannelError,
24 #[error("{message}")]
30 JsError {
31 name: String,
33 message: String,
35 stack: String,
37 },
38 #[error("Internal Error `{0}` occurred, this is a bug in the library please open an issue at https://github.com/JamiiDao/SolanaWalletAdapter/issues")]
44 InternalError(String),
45 #[error("A value of `undefined` or `null` was encountered")]
47 ValueNotFound,
48 #[error("A value of `{0}` was expected but it does not exist in the `JsValue`")]
50 ExpectedValueNotFound(String),
51 #[error("Unable to access browser window")]
53 MissingAccessToBrowserWindow,
54 #[error("Unable to access browser document")]
56 MissingAccessToBrowserDocument,
57 #[error("Unsupported Commitment level `{0}`. Only `processed`, `confirmed` and `finalized` commitments are supported by Solana clusters")]
59 UnsupportedCommitment(String),
60 #[error("The wallet version `{0}` is invalid, expected SemVer version")]
62 InvalidWalletVersion(String),
63 #[error("Unexpected SemVer number `{0}` to parse to a `u8`")]
65 InvalidSemVerNumber(String),
66 #[error("The byte length should be equal to 32 bytes in length")]
68 Expected32ByteLength,
69 #[error("The byte length should be equal to 64 bytes in length")]
71 Expected64ByteLength,
72 #[error("The version was not found")]
74 VersionNotFound,
75 #[error("The feature `{0}` is not supported as a standard or solana namespace feature")]
77 UnsupportedWalletFeature(String),
78 #[error("Encountered an unsupported transaction version. Only `legacy` and `version zero` transactions are supported.")]
81 UnsupportedTransactionVersion,
82 #[error("Legacy transaction versions need to be supported yet the encountered wallet does not do this.")]
84 LegacyTransactionSupportRequired,
85 #[error("The blockchain `{0}` is not supported")]
87 UnsupportedChain(String),
88 #[error("The `connect` function of the `standard:connect` namespace was not found while parsing a wallet")]
90 MissingConnectFunction,
91 #[error("Attempted to connect to a wallet that does not exist or is yet to be registered")]
93 WalletNotFound,
94 #[error(
96 "Attempted to connect to an account that does not exist or might have been disconnected"
97 )]
98 AccountNotFound,
99 #[error("Unable to connect to a wallet. Error `{0}` request")]
101 WalletConnectError(String),
102 #[error("The connect method did not return any accounts")]
104 ConnectHasNoAccounts,
105 #[error("The wallet `standard:disconnect` feature is missing")]
107 MissingDisconnectFunction,
108 #[error("The `accounts` method to get the accounts connected to a wallet is missing from wallet `{0}`")]
110 MissingGetAccountsFunction(String),
111 #[error("Wallet Disconnect error - `{0}`")]
113 WalletDisconnectError(String),
114 #[error("Encountered `standard:events` error `{0}`")]
116 StandardEventsError(String),
117 #[error("Called The Function for `standard:events` yet the wallet does not provide it")]
119 MissingStandardEventsFunction,
120 #[error("The wallet did not register a signIn function for `solana:signIn` namespece")]
122 MissingSignInFunction,
123 #[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")]
125 ExpiryTimeEarlierThanIssuedTime,
126 #[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")]
128 NotBeforeTimeEarlierThanIssuedTime,
129 #[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")]
131 NotBeforeTimeLaterThanExpirationTime,
132 #[error("The expiration time is set to expire in the past")]
134 ExpirationTimeIsInThePast,
135 #[error("NotBefore time is set in the past")]
137 NotBeforeTimeIsInThePast,
138 #[error("Invalid Base58 Address")]
140 InvalidBase58Address,
141 #[error("The nonce is required to be at least 8 characters long")]
143 NonceMustBeAtLeast8Characters,
144 #[error("Invalid ISO 8601 timestamp `{0}. Only timestamps in the format specified by ISO8601 are supported.")]
146 InvalidISO8601Timestamp(String),
147 #[error("The message signed by the wallet is not the same as the message sent to the wallet for signing")]
149 MessageResponseMismatch,
150 #[error("The Ed25519 Signature is invalid for the signed message and public key")]
152 InvalidSignature,
153 #[error("The bytes provided for the Ed25519 Signature are invalid")]
155 InvalidEd25519SignatureBytes,
156 #[error("The bytes provided for the Ed25519 Public Key are invalid")]
158 InvalidEd25519PublicKeyBytes,
159 #[error("The function call to Sign A Message Is Missing")]
161 MissingSignMessageFunction,
162 #[error("The message sent to the wallet to be signed is different from the message the wallet responded with")]
164 SignedMessageMismatch,
165 #[error("The Wallet returned an empty array of signed messages")]
167 ReceivedAnEmptySignedMessagesArray,
168 #[error("The `solana:signTransaction` function is missing in the provided wallet")]
170 MissingSignTransactionFunction,
171 #[error("The `sendAndSignTransaction` method did not return any signature")]
173 SendAndSignTransactionSignatureEmpty,
174 #[error("SystemTime::checked_add(expiration_time_milliseconds) overflow")]
176 SystemTimeCheckedAddOverflow,
177 #[error("An operation resulted in an error `{0}`.")]
182 Op(String),
183}
184
185impl From<JsValue> for WalletError {
186 fn from(value: JsValue) -> Self {
187 let reflect = |key: &str| -> Result<String, Self> {
188 Reflect::get(&value, &key.into())
189 .map_err(|error: JsValue| WalletError::InternalError(format!("{:?}", &error)))?
190 .as_string()
191 .ok_or(WalletError::InternalError(format!(
192 "Reflecting `{key}` in `{value:?}` did not yield a JsString"
193 )))
194 };
195
196 let name = match reflect("name") {
197 Ok(inner) => inner,
198 Err(error) => return error,
199 };
200
201 let stack = match reflect("stack") {
202 Ok(inner) => inner,
203 Err(error) => return error,
204 };
205 let message = match reflect("message") {
206 Ok(inner) => inner,
207 Err(error) => return error,
208 };
209
210 Self::JsError {
211 message,
212 name,
213 stack,
214 }
215 }
216}
217
218impl From<WalletUtilsError> for WalletError {
219 fn from(value: WalletUtilsError) -> Self {
220 match value {
221 WalletUtilsError::SystemTimeCheckedAddOverflow => Self::SystemTimeCheckedAddOverflow,
222 WalletUtilsError::ExpiryTimeEarlierThanIssuedTime => {
223 Self::ExpiryTimeEarlierThanIssuedTime
224 }
225 WalletUtilsError::ExpirationTimeIsInThePast => Self::ExpirationTimeIsInThePast,
226 WalletUtilsError::NotBeforeTimeEarlierThanIssuedTime => {
227 Self::NotBeforeTimeEarlierThanIssuedTime
228 }
229 WalletUtilsError::NotBeforeTimeIsInThePast => todo!(),
230 WalletUtilsError::NotBeforeTimeLaterThanExpirationTime => {
231 Self::NotBeforeTimeLaterThanExpirationTime
232 }
233 WalletUtilsError::InvalidISO8601Timestamp(value) => {
234 Self::InvalidISO8601Timestamp(value)
235 }
236 WalletUtilsError::InvalidBase58Address => Self::InvalidBase58Address,
237 WalletUtilsError::InvalidEd25519PublicKeyBytes => Self::InvalidEd25519PublicKeyBytes,
238 WalletUtilsError::InvalidSignature => Self::InvalidSignature,
239 WalletUtilsError::Expected64ByteLength => Self::Expected64ByteLength,
240 WalletUtilsError::Expected32ByteLength => Self::Expected32ByteLength,
241 WalletUtilsError::NonceMustBeAtLeast8Characters => Self::NonceMustBeAtLeast8Characters,
242 WalletUtilsError::MessageResponseMismatch => Self::MessageResponseMismatch,
243 }
244 }
245}