wallet_adapter/wallet_ser_der/standard_features/
features.rs

1use wallet_adapter_common::{
2    feature_support::FeatureSupport,
3    standardized_events::{
4        SOLANA_SIGN_AND_SEND_TRANSACTION_IDENTIFIER, SOLANA_SIGN_IN_IDENTIFIER,
5        SOLANA_SIGN_MESSAGE_IDENTIFIER, SOLANA_SIGN_TRANSACTION_IDENTIFIER,
6        STANDARD_CONNECT_IDENTIFIER, STANDARD_DISCONNECT_IDENTIFIER, STANDARD_EVENTS_IDENTIFIER,
7    },
8};
9
10use crate::{
11    Connect, Disconnect, Reflection, SemverVersion, SignIn, SignMessage, SignTransaction,
12    StandardEvents, WalletError, WalletResult,
13};
14
15/// All the features of `standard` and `solana` events as specified
16/// in the wallet standard. These features are contained within a
17/// [crate::Wallet] struct allowing to check if a wallet supports a certain
18/// feature and also calling the callback functions to make requests to a browser wallet.
19#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct Features {
21    /// standard:connect
22    pub(crate) connect: Connect,
23    /// standard:disconnect
24    pub(crate) disconnect: Disconnect,
25    /// standard:events
26    pub(crate) events: StandardEvents,
27    /// solana:signAndSendTransaction
28    pub(crate) sign_and_send_tx: SignTransaction,
29    /// solana:signTransaction
30    pub(crate) sign_tx: SignTransaction,
31    /// solana:signMessage
32    pub(crate) sign_message: SignMessage,
33    /// solana:signIn
34    pub(crate) sign_in: Option<SignIn>,
35    /// Non-standard features
36    extensions: Vec<String>,
37}
38
39impl Features {
40    /// Parse all the features from a wallet described as a [web_sys::wasm_bindgen::JsValue]
41    pub(crate) fn parse(reflection: &Reflection) -> WalletResult<(Self, FeatureSupport)> {
42        let features_keys = reflection.object_to_vec_string("features")?;
43        let features_object = Reflection::new_from_str(reflection.get_inner(), "features")?;
44
45        let mut features = Features::default();
46        let mut supported_features = FeatureSupport::default();
47
48        features_keys.into_iter().try_for_each(|feature| {
49            let inner_object = features_object.reflect_inner(&feature)?;
50            let inner_object = Reflection::new(inner_object)?;
51
52            if feature.starts_with("standard:") || feature.starts_with("solana:") {
53                let version = SemverVersion::from_jsvalue(&inner_object)?;
54
55                if feature == STANDARD_CONNECT_IDENTIFIER {
56                    features.connect = Connect::new(&inner_object, version)?;
57                    supported_features.connect = true;
58                } else if feature == STANDARD_DISCONNECT_IDENTIFIER {
59                    features.disconnect = Disconnect::new(&inner_object, version)?;
60                    supported_features.disconnect = true;
61                } else if feature == STANDARD_EVENTS_IDENTIFIER {
62                    features.events = StandardEvents::new(&inner_object, version)?;
63                    supported_features.events = true;
64                } else if feature == SOLANA_SIGN_AND_SEND_TRANSACTION_IDENTIFIER {
65                    features.sign_and_send_tx =
66                        SignTransaction::new_sign_and_send_tx(&inner_object, version)?;
67                    supported_features.sign_and_send_tx = true;
68                } else if feature == SOLANA_SIGN_TRANSACTION_IDENTIFIER {
69                    features.sign_tx = SignTransaction::new_sign_tx(&inner_object, version)?;
70                    supported_features.sign_tx = true;
71                } else if feature == SOLANA_SIGN_MESSAGE_IDENTIFIER {
72                    features.sign_message = SignMessage::new(&inner_object, version)?;
73                    supported_features.sign_message = true;
74                } else if feature == SOLANA_SIGN_IN_IDENTIFIER {
75                    features
76                        .sign_in
77                        .replace(SignIn::new(&inner_object, version)?);
78                    supported_features.sign_in = true;
79                } else {
80                    return Err(WalletError::UnsupportedWalletFeature(feature));
81                }
82            } else {
83                features.extensions.push(feature);
84            }
85
86            Ok(())
87        })?;
88
89        Ok((features, supported_features))
90    }
91
92    /// Get all extensions on the wallet
93    pub fn extensions(&self) -> &[String] {
94        &self.extensions
95    }
96}