1#![allow(missing_docs)]
4pub mod errors;
26
27use crate::errors::KeyringErrorAdapter;
28use crate::errors::TerraRustWalletError;
31use secp256k1::Secp256k1;
32use serde::{Deserialize, Serialize};
33use terra_rust_api::{PrivateKey, PublicKey};
34
35#[derive(Deserialize, Serialize, Debug)]
36pub struct WalletInternal {
38 pub keys: Vec<String>,
39}
40#[derive(Deserialize, Serialize, Debug)]
41pub struct WalletListInternal {
43 pub wallets: Vec<String>,
44}
45
46#[derive(Clone)]
51pub struct Wallet<'a> {
52 pub name: &'a str,
53}
54impl<'a> Wallet<'a> {
55 pub fn new(wallet_name: &'a str) -> Result<Wallet<'a>, TerraRustWalletError> {
58 log::debug!("Creating new wallet {}", wallet_name);
59 let wallet = Wallet::create(wallet_name);
60 let wallet_list_name = &wallet.full_list_name();
61 let keyring = keyring::Entry::new(wallet_name, wallet_list_name);
62 let wallet_internal = WalletInternal { keys: vec![] };
63 keyring
64 .set_password(&serde_json::to_string(&wallet_internal)?)
65 .map_err(KeyringErrorAdapter::from)?;
66 let string_key_name: String = String::from(wallet_name);
67
68 match Wallet::get_wallets() {
69 Ok(old_list) => {
70 let mut new_list: Vec<String> = vec![];
71 for s in old_list {
72 if s.ne(wallet_name) {
73 new_list.push(s);
74 }
75 }
76 new_list.push(string_key_name);
77 let wallet_list = WalletListInternal { wallets: new_list };
78 Wallet::set_wallets(&wallet_list)?;
79 }
80 Err(_) => {
81 let wallet_list = WalletListInternal {
83 wallets: vec![string_key_name],
84 };
85 Wallet::set_wallets(&wallet_list)?;
86 }
87 }
88
89 Ok(wallet)
90 }
91 pub fn create(wallet: &'a str) -> Wallet<'a> {
93 Wallet { name: wallet }
94 }
95 pub fn get_private_key<C: secp256k1::Signing + secp256k1::Context>(
97 &self,
98 secp: &'a Secp256k1<C>,
99 key_name: &'a str,
100 seed: Option<&'a str>,
101 ) -> Result<PrivateKey, TerraRustWalletError> {
102 let full_key_name = self.full_key_name(key_name);
103 let keyring = keyring::Entry::new(self.name, &full_key_name);
104 let phrase = &keyring.get_password()?; match seed {
107 None => Ok(PrivateKey::from_words(secp, phrase, 0, 0)?),
108 Some(seed_str) => Ok(PrivateKey::from_words_seed(secp, phrase, seed_str)?),
109 }
110 }
111 pub fn get_public_key<C: secp256k1::Signing + secp256k1::Context>(
113 &self,
114 secp: &Secp256k1<C>,
115 key_name: &str,
116 seed: Option<&str>,
117 ) -> Result<PublicKey, TerraRustWalletError> {
118 let private_key: PrivateKey = self.get_private_key(secp, key_name, seed)?;
119
120 let pub_key = private_key.public_key(secp);
121 Ok(pub_key)
122 }
123
124 pub fn get_account<C: secp256k1::Signing + secp256k1::Context>(
126 &self,
127 secp: &Secp256k1<C>,
128 key_name: &str,
129 seed: Option<&str>,
130 ) -> Result<String, TerraRustWalletError> {
131 let pub_key = self.get_public_key(secp, key_name, seed)?;
132 let account = pub_key.account()?;
133 Ok(account)
134 }
135 pub fn store_key(&self, key_name: &str, pk: &PrivateKey) -> Result<bool, TerraRustWalletError> {
137 let full_key_name = self.full_key_name(key_name);
138
139 let keyring = keyring::Entry::new(self.name, &full_key_name);
140 keyring.set_password(pk.words().unwrap())?; let old_list = self.get_keys()?;
142 let string_key_name: String = String::from(key_name);
143 let mut new_list: Vec<String> = vec![];
144 for s in old_list {
145 if s.ne(key_name) {
146 new_list.push(s);
147 }
148 }
149
150 new_list.push(string_key_name);
151 let wallet_internal = WalletInternal { keys: new_list };
152 self.set_keys(&wallet_internal)?;
153
154 Ok(true)
155 }
156 pub fn delete_key(&self, key_name: &str) -> Result<bool, TerraRustWalletError> {
158 let full_key_name = self.full_key_name(key_name);
159 let keyring = keyring::Entry::new(self.name, &full_key_name);
160 keyring.delete_password()?; let old_list = self.get_keys()?;
162 let mut new_list = vec![];
163 for s in old_list {
164 if s.ne(key_name) {
165 new_list.push(s);
166 }
167 }
168 let wallet_internal = WalletInternal { keys: new_list };
169 self.set_keys(&wallet_internal)?;
170 Ok(true)
171 }
172 pub fn list(&self) -> Result<Vec<String>, TerraRustWalletError> {
174 self.get_keys()
175 }
176
177 pub fn delete(&self) -> Result<(), TerraRustWalletError> {
179 let keys = self.get_keys()?;
180 for key in keys {
181 log::debug!("Deleting Key {} in wallet {}", key, &self.name);
182 self.delete_key(&key)?;
183 }
184 let wallet_list_name = self.full_list_name();
185 let keyring = keyring::Entry::new(self.name, &wallet_list_name);
186 keyring.delete_password()?; let old_list = Wallet::get_wallets()?;
188 let mut new_list: Vec<String> = vec![];
190 for s in old_list {
191 if s.ne(self.name) {
192 new_list.push(s);
193 }
194 }
195 let wallet_list = WalletListInternal { wallets: new_list };
196 Wallet::set_wallets(&wallet_list)?;
197 Ok(())
198 }
199 fn full_key_name(&self, key_name: &'a str) -> String {
201 format!("TERRA-RUST-{}-{}", self.name, key_name)
202 }
203 fn full_list_name(&self) -> String {
205 format!("TERRA-RUST-{}_KEYS", self.name)
206 }
207 fn wallet_list_name() -> String {
209 "TERRA-RUST_WALLETS".to_string()
210 }
211
212 fn get_keys(&self) -> Result<Vec<String>, TerraRustWalletError> {
214 let wallet_list_name = self.full_list_name();
215 let keyring = keyring::Entry::new(self.name, &wallet_list_name);
216 let pass = keyring.get_password()?;
217 let wallet_internal: WalletInternal = serde_json::from_str(&pass)?;
223 Ok(wallet_internal.keys)
224 }
225
226 pub fn get_wallets() -> Result<Vec<String>, TerraRustWalletError> {
228 let wallet_list_name = Wallet::wallet_list_name();
229 let keyring = keyring::Entry::new(&wallet_list_name, "wallets");
230
231 let wallet_internal: WalletListInternal = serde_json::from_str(&keyring.get_password()?)?; Ok(wallet_internal.wallets)
233 }
234
235 fn set_keys(&self, int: &WalletInternal) -> Result<(), TerraRustWalletError> {
237 let wallet_list_name = self.full_list_name();
238 let keyring = keyring::Entry::new(self.name, &wallet_list_name);
239
240 keyring.set_password(&serde_json::to_string(int)?)?; Ok(())
242 }
243 fn set_wallets(int: &WalletListInternal) -> Result<(), TerraRustWalletError> {
245 let wallet_list_name = Wallet::wallet_list_name();
246 let keyring = keyring::Entry::new(&wallet_list_name, "wallets");
247
248 keyring.set_password(&serde_json::to_string(int)?)?; Ok(())
250 }
251}
252
253#[cfg(test)]
254mod tst {
255 use super::*;
256
257 #[test]
258 pub fn test_wallet_create_delete() -> anyhow::Result<()> {
259 let wallet = Wallet::new("PFC-Test Wallet")?;
260 let key_list = wallet.get_keys()?;
261 assert!(key_list.is_empty());
262 wallet.delete()?;
263 Ok(())
264 }
265 #[test]
266 pub fn test_wallet_add_del() -> anyhow::Result<()> {
267 let str_1 = "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius";
268 let str_2 = "wonder caution square unveil april art add hover spend smile proud admit modify old copper throw crew happy nature luggage reopen exhibit ordinary napkin";
269
270 let s = Secp256k1::new();
271 let pk = PrivateKey::from_words(&s, str_1, 0, 0)?;
272 let pk2 = PrivateKey::from_words(&s, str_2, 0, 0)?;
273
274 let wallet = Wallet::new("PFC-Test Wallet")?;
275 wallet.store_key("PFC-Test-Key", &pk)?;
276 let key_list = wallet.get_keys()?;
277 assert_eq!(key_list.len(), 1);
278
279 wallet.store_key("PFC-Test-Key-2", &pk2)?;
280 let mut key_list = wallet.get_keys()?;
281 assert_eq!(key_list.len(), 2);
282
283 key_list.sort();
284 assert_eq!(key_list.join(","), "PFC-Test-Key,PFC-Test-Key-2");
285
286 let pk_get = wallet.get_private_key(&s, "PFC-Test-Key", None)?;
287 assert_eq!(pk_get.words().unwrap(), str_1);
288
289 wallet.delete_key("PFC-Test-Key")?;
290 let key_list = wallet.get_keys()?;
291 assert_eq!(key_list.len(), 1);
292 assert_eq!(key_list.join(","), "PFC-Test-Key-2");
293
294 wallet.delete()?;
295 Ok(())
296 }
297}