Skip to main content

wallet_adapter_common/
wallet.rs

1use std::borrow::Cow;
2
3use crate::{
4    chains::ChainSupport, clusters::Cluster, feature_support::FeatureSupport, SemverVersion,
5    WalletAccountData,
6};
7
8/// Wallet information without any browser function calls for `wallet-adapter` standard operations
9#[derive(Clone, Default, PartialEq, Eq)]
10pub struct WalletData {
11    name: Cow<'static, str>,
12    version: SemverVersion,
13    icon: Option<Cow<'static, str>>,
14    accounts: Vec<WalletAccountData>,
15    chains: Vec<Cluster>,
16    // Convenience field, instead of going through the `features` field
17    supported_features: FeatureSupport,
18    // Convenience field, instead of iteration through the `chains` field
19    supported_chains: ChainSupport,
20}
21
22impl WalletData {
23    /// Instantiate a new [WalletData]
24    pub fn new() -> Self {
25        Self::default()
26    }
27
28    /// Set the name of the wallet
29    pub fn set_name(mut self, name: &str) -> Self {
30        self.name = Cow::Owned(name.to_string());
31
32        self
33    }
34
35    /// Set the [Semver version](SemverVersion) of the wallet
36    pub fn set_version(mut self, version: SemverVersion) -> Self {
37        self.version = version;
38
39        self
40    }
41
42    /// Set the icon of the wallet.
43    /// Should be in Base64 URL web format `data:image/${'svg+xml' | 'webp' | 'png' | 'gif'};base64,${string}`
44    pub fn set_icon(mut self, icon: Option<impl ToString>) -> Self {
45        icon.map(|value| self.icon.replace(Cow::Owned(value.to_string())));
46
47        self
48    }
49
50    /// Add a [Wallet account](WalletAccountData) data
51    pub fn add_account(mut self, account: WalletAccountData) -> Self {
52        self.accounts.push(account);
53
54        self
55    }
56
57    /// Add multiple [Wallet account](WalletAccountData) data(s)
58    pub fn add_accounts(mut self, accounts: &[WalletAccountData]) -> Self {
59        self.accounts.extend_from_slice(accounts);
60
61        self
62    }
63
64    /// Replace all [Wallet account](WalletAccountData) data
65    pub fn replace_accounts(mut self, accounts: Vec<WalletAccountData>) -> Self {
66        self.accounts = accounts;
67
68        self
69    }
70
71    /// Add a [Cluster]
72    pub fn add_chain(mut self, chain: Cluster) -> Self {
73        self.chains.push(chain);
74
75        self
76    }
77
78    /// Add multiple [Cluster]s
79    pub fn add_chains(mut self, chains: &[Cluster]) -> Self {
80        self.chains.extend_from_slice(chains);
81
82        self
83    }
84
85    /// Replace existing [Cluster]s
86    pub fn replace_chains(mut self, chains: Vec<Cluster>) -> Self {
87        self.chains = chains;
88
89        self
90    }
91
92    /// Set the supported wallet [features](FeatureSupport)
93    pub fn set_supported_features(mut self, supported_features: FeatureSupport) -> Self {
94        self.supported_features = supported_features;
95
96        self
97    }
98
99    /// Set the [chains](ChainSupport) supported by the wallet
100    pub fn set_supported_chains(mut self, supported_chains: ChainSupport) -> Self {
101        self.supported_chains = supported_chains;
102
103        self
104    }
105
106    /// Get the accounts provided by the wallet
107    pub fn accounts(&self) -> &[WalletAccountData] {
108        &self.accounts
109    }
110
111    /// Get the chains supported by the wallet
112    pub fn chains(&self) -> &[Cluster] {
113        &self.chains
114    }
115
116    /// Check whether the wallet supports mainnet cluster
117    pub fn mainnet(&self) -> bool {
118        self.supported_chains.mainnet
119    }
120
121    /// Check whether the wallet supports devnet cluster
122    pub fn devnet(&self) -> bool {
123        self.supported_chains.devnet
124    }
125
126    /// Check whether the wallet supports testnet cluster
127    pub fn testnet(&self) -> bool {
128        self.supported_chains.testnet
129    }
130
131    /// Check whether the wallet supports localnet cluster
132    pub fn localnet(&self) -> bool {
133        self.supported_chains.localnet
134    }
135
136    /// Check whether the wallet supports `standard:connect` feature
137    pub fn standard_connect(&self) -> bool {
138        self.supported_features.connect
139    }
140
141    /// Check whether the wallet supports `standard:disconnect` feature
142    pub fn standard_disconnect(&self) -> bool {
143        self.supported_features.disconnect
144    }
145
146    /// Check whether the wallet supports `standard:events` feature
147    pub fn standard_events(&self) -> bool {
148        self.supported_features.events
149    }
150
151    /// Check whether the wallet supports `solana:signIn` feature
152    pub fn solana_signin(&self) -> bool {
153        self.supported_features.sign_in
154    }
155
156    /// Check whether the wallet supports `solana:signMessage` feature
157    pub fn solana_sign_message(&self) -> bool {
158        self.supported_features.sign_message
159    }
160
161    /// Check whether the wallet supports `solana:signAndSendTransaction` feature
162    pub fn solana_sign_and_send_transaction(&self) -> bool {
163        self.supported_features.sign_and_send_tx
164    }
165
166    /// Check whether the wallet supports `solana:signTransaction` feature
167    pub fn solana_sign_transaction(&self) -> bool {
168        self.supported_features.sign_tx
169    }
170
171    /// Get the optional Wallet Icon
172    pub fn icon(&self) -> Option<&Cow<'static, str>> {
173        self.icon.as_ref()
174    }
175
176    /// Get the name of the wallet
177    pub fn name(&self) -> &str {
178        &self.name
179    }
180
181    /// Get the version of the wallet standard that the wallet supports
182    pub fn version(&self) -> &SemverVersion {
183        &self.version
184    }
185}
186
187impl core::fmt::Debug for WalletData {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        let chains = self
190            .chains
191            .iter()
192            .map(|cluster| cluster.chain())
193            .collect::<Vec<&str>>();
194
195        f.debug_struct("Wallet")
196            .field("name", &self.name)
197            .field("version", &self.version)
198            .field("icon", &self.icon)
199            .field("accounts", &self.accounts)
200            .field("chains", &chains)
201            .finish()
202    }
203}
204
205impl PartialOrd for WalletData {
206    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
207        Some(self.cmp(other))
208    }
209}
210
211impl Ord for WalletData {
212    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
213        self.name
214            .as_bytes()
215            .cmp(other.name.as_bytes())
216            .then(self.version.cmp(&other.version))
217    }
218}
219
220impl core::hash::Hash for WalletData {
221    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
222        self.name.as_bytes().hash(state);
223        self.version.hash(state);
224    }
225}