kaspa_cli_lib/modules/
wallet.rs

1use 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}