1use std::sync::Arc;
2
3use solana_sdk::{
4 hash::Hash,
5 message::VersionedMessage,
6 pubkey::Pubkey,
7 signature::{keypair_from_seed, Keypair, Signature},
8 signer::Signer,
9 transaction::VersionedTransaction,
10};
11
12use crate::{
13 constants::{self},
14 types::{SdkError, SdkResult},
15 utils,
16};
17
18#[derive(Clone, Debug)]
20pub enum Mode {
21 Normal,
23 ReadOnly,
25 Delegated,
27}
28
29#[derive(Clone, Debug)]
42pub struct Wallet {
43 signer: Arc<Keypair>,
45 authority: Pubkey,
48 stats: Pubkey,
50 mode: Mode,
52}
53
54impl Wallet {
55 pub fn is_delegated(&self) -> bool {
57 matches!(self.mode, Mode::Delegated)
58 }
59 pub fn is_read_only(&self) -> bool {
61 matches!(self.mode, Mode::ReadOnly)
62 }
63 pub fn try_from_str(path_or_key: &str) -> SdkResult<Self> {
72 let authority = utils::load_keypair_multi_format(path_or_key)?;
73 Ok(Self::new(authority))
74 }
75 pub fn read_only(authority: Pubkey) -> Self {
77 Self {
78 signer: Arc::new(Keypair::new()),
79 authority,
80 stats: Wallet::derive_stats_account(&authority),
81 mode: Mode::ReadOnly,
82 }
83 }
84 pub fn from_seed_bs58(seed: &str) -> Self {
91 let authority = Keypair::from_base58_string(seed);
92 Self::new(authority)
93 }
94 pub fn from_seed(seed: &[u8]) -> SdkResult<Self> {
96 let authority = keypair_from_seed(seed).map_err(|_| SdkError::InvalidSeed)?;
97 Ok(Self::new(authority))
98 }
99 pub fn new(authority: Keypair) -> Self {
103 Self {
104 stats: Wallet::derive_stats_account(&authority.pubkey()),
105 authority: authority.pubkey(),
106 signer: Arc::new(authority),
107 mode: Mode::Normal,
108 }
109 }
110 #[deprecated = "use Wallet::delegated"]
114 pub fn to_delegated(&mut self, authority: Pubkey) {
115 self.stats = Wallet::derive_stats_account(&authority);
116 self.authority = authority;
117 self.mode = Mode::Delegated;
118 }
119 pub fn delegated(signer: Keypair, authority: Pubkey) -> Self {
124 Self {
125 signer: Arc::new(signer),
126 stats: Wallet::derive_stats_account(&authority),
127 authority,
128 mode: Mode::Delegated,
129 }
130 }
131 pub fn derive_user_account(authority: &Pubkey, sub_account_id: u16) -> Pubkey {
133 let (account_drift_pda, _seed) = Pubkey::find_program_address(
134 &[
135 &b"user"[..],
136 authority.as_ref(),
137 &sub_account_id.to_le_bytes(),
138 ],
139 &constants::PROGRAM_ID,
140 );
141 account_drift_pda
142 }
143
144 pub fn derive_stats_account(account: &Pubkey) -> Pubkey {
146 let (account_drift_pda, _seed) = Pubkey::find_program_address(
147 &[&b"user_stats"[..], account.as_ref()],
148 &constants::PROGRAM_ID,
149 );
150 account_drift_pda
151 }
152
153 pub fn derive_swift_order_account(authority: &Pubkey) -> Pubkey {
155 let (account_drift_pda, _seed) = Pubkey::find_program_address(
156 &[&b"SIGNED_MSG"[..], authority.as_ref()],
157 &constants::PROGRAM_ID,
158 );
159 account_drift_pda
160 }
161
162 pub fn sign_tx(
170 &self,
171 mut message: VersionedMessage,
172 recent_block_hash: Hash,
173 ) -> SdkResult<VersionedTransaction> {
174 message.set_recent_blockhash(recent_block_hash);
175 let signer: &dyn Signer = self.signer.as_ref();
176 match self.mode {
177 Mode::ReadOnly => Err(SdkError::WalletSigningDisabled),
178 _ => VersionedTransaction::try_new(message, &[signer]).map_err(Into::into),
179 }
180 }
181
182 pub fn sign_message(&self, message: &[u8]) -> SdkResult<Signature> {
184 let signer: &dyn Signer = self.signer.as_ref();
185 match self.mode {
186 Mode::ReadOnly => Err(SdkError::WalletSigningDisabled),
187 _ => Ok(signer.sign_message(message)),
188 }
189 }
190 pub fn authority(&self) -> &Pubkey {
192 &self.authority
193 }
194 pub fn signer(&self) -> Pubkey {
196 self.signer.pubkey()
197 }
198 pub fn stats(&self) -> &Pubkey {
200 &self.stats
201 }
202 pub fn default_sub_account(&self) -> Pubkey {
204 self.sub_account(0)
205 }
206 pub fn sub_account(&self, sub_account_id: u16) -> Pubkey {
208 Self::derive_user_account(self.authority(), sub_account_id)
209 }
210}
211
212impl From<Keypair> for Wallet {
213 fn from(value: Keypair) -> Self {
214 Self::new(value)
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 fn wallet_read_only() {
224 let keypair = Keypair::new();
225 let ro = Wallet::read_only(keypair.pubkey());
226
227 let rw = Wallet::new(keypair);
228 assert_eq!(rw.authority, ro.authority);
229 assert_eq!(rw.stats, ro.stats);
230 assert_eq!(rw.default_sub_account(), ro.default_sub_account());
231 }
232}