kaspa_cli_lib/modules/
wallet.rs1use crate::imports::*;
2use crate::wizards;
3
4#[derive(Default, Handler)]
5#[help("Wallet management operations")]
6pub struct Wallet;
7
8impl Wallet {
9 async fn main(self: Arc<Self>, ctx: &Arc<dyn Context>, mut argv: Vec<String>, cmd: &str) -> Result<()> {
10 let ctx = ctx.clone().downcast_arc::<KaspaCli>()?;
11
12 let guard = ctx.wallet().guard();
13 let guard = guard.lock().await;
14
15 if argv.is_empty() {
16 return self.display_help(ctx, argv).await;
17 }
18
19 let op = argv.remove(0);
20 match op.as_str() {
21 "list" => {
22 let wallets = ctx.store().wallet_list().await?;
23 if wallets.is_empty() {
24 tprintln!(ctx, "No wallets found");
25 } else {
26 tprintln!(ctx, "");
27 tprintln!(ctx, "Wallets:");
28 tprintln!(ctx, "");
29 for wallet in wallets {
30 if let Some(title) = wallet.title {
31 tprintln!(ctx, " {}: {}", wallet.filename, title);
32 } else {
33 tprintln!(ctx, " {}", wallet.filename);
34 }
35 }
36 tprintln!(ctx, "");
37 }
38 }
39 "create" | "import" => {
40 let wallet_name = if argv.is_empty() {
41 None
42 } else {
43 let name = argv.remove(0);
44 let name = name.trim().to_string();
45 let name_check = name.to_lowercase();
46 if name_check.as_str() == "wallet" {
47 return Err(Error::custom("Wallet name cannot be 'wallet'"));
48 }
49 Some(name)
50 };
51
52 let wallet_name = wallet_name.as_deref();
53 let import_with_mnemonic = op.as_str() == "import";
54 wizards::wallet::create(&ctx, guard.into(), wallet_name, import_with_mnemonic).await?;
55 }
56 "open" => {
57 let name = if let Some(name) = argv.first().cloned() {
58 let name_check = name.to_lowercase();
59
60 if name_check.as_str() == "wallet" {
61 tprintln!(ctx, "you can not have a wallet named 'wallet'...");
62 tprintln!(ctx, "perhaps you are looking to use 'open <name>'");
63 return Ok(());
64 }
65 Some(name)
66 } else {
67 ctx.wallet().settings().get(WalletSettings::Wallet).clone()
68 };
69
70 let (wallet_secret, _) = ctx.ask_wallet_secret(None).await?;
71 let _ = ctx.notifier().show(Notification::Processing).await;
72 let args = WalletOpenArgs::default_with_legacy_accounts();
73 ctx.wallet().open(&wallet_secret, name, args, &guard).await?;
74 ctx.wallet().activate_accounts(None, &guard).await?;
75 }
76 "close" => {
77 ctx.wallet().close().await?;
78 }
79 "hint" => {
80 if !argv.is_empty() {
81 let re = regex::Regex::new(r"wallet\s+hint\s+").unwrap();
82 let hint = re.replace(cmd, "");
83 let hint = hint.trim();
84 let store = ctx.store();
85 if hint == "remove" {
86 tprintln!(ctx, "Hint is empty - removing wallet hint");
87 store.set_user_hint(None).await?;
88 } else {
89 store.set_user_hint(Some(hint.into())).await?;
90 }
91 } else {
92 tprintln!(ctx, "usage:\n'wallet hint <text>' or 'wallet hint remove' to remove the hint");
93 }
94 }
95 v => {
96 tprintln!(ctx, "unknown command: '{v}'");
97 return self.display_help(ctx, argv).await;
98 }
99 }
100
101 Ok(())
102 }
103
104 async fn display_help(self: Arc<Self>, ctx: Arc<KaspaCli>, _argv: Vec<String>) -> Result<()> {
105 ctx.term().help(
106 &[
107 ("list", "List available local wallet files"),
108 ("create [<name>]", "Create a new bip32 wallet"),
109 (
110 "import [<name>]",
111 "Create a wallet from an existing mnemonic (bip32 only). \r\n\r\n\
112 To import legacy wallets (KDX or kaspanet) please create \
113 a new bip32 wallet and use the 'account import' command. \
114 Legacy wallets can only be imported as accounts. \
115 \r\n",
116 ),
117 ("open [<name>]", "Open an existing wallet (shorthand: 'open [<name>]')"),
118 ("close", "Close an opened wallet (shorthand: 'close')"),
119 ("hint", "Change the wallet phishing hint"),
120 ],
121 None,
122 )?;
123
124 Ok(())
125 }
126}