kaspa_cli_lib/modules/
history.rs1use crate::imports::*;
2use kaspa_consensus_core::tx::TransactionId;
3use kaspa_wallet_core::error::Error as WalletError;
4use kaspa_wallet_core::storage::Binding;
5#[derive(Default, Handler)]
6#[help("Display transaction history")]
7pub struct History;
8
9impl History {
10 async fn main(self: Arc<Self>, ctx: &Arc<dyn Context>, mut argv: Vec<String>, _cmd: &str) -> Result<()> {
11 let ctx = ctx.clone().downcast_arc::<KaspaCli>()?;
12
13 let guard = ctx.wallet().guard();
14 let guard = guard.lock().await;
15
16 if argv.is_empty() {
17 self.display_help(ctx, argv).await?;
18 return Ok(());
19 }
20
21 let account = ctx.account().await?;
22 let network_id = ctx.wallet().network_id()?;
23 let binding = Binding::from(&account);
24 let current_daa_score = ctx.wallet().current_daa_score();
25
26 let (last, include_utxo) = match argv.remove(0).as_str() {
27 "lookup" => {
28 let transaction_id = if argv.is_empty() {
29 tprintln!(ctx, "usage: history lookup <transaction id>");
30 return Ok(());
31 } else {
32 argv.remove(0)
33 };
34
35 let txid = TransactionId::from_hex(transaction_id.as_str())?;
36 let store = ctx.wallet().store().as_transaction_record_store()?;
37 match store.load_single(&binding, &network_id, &txid).await {
38 Ok(tx) => {
39 let lines = tx
40 .format_transaction_with_args(
41 &ctx.wallet(),
42 None,
43 current_daa_score,
44 true,
45 true,
46 Some(account.clone()),
47 &guard,
48 )
49 .await;
50 lines.iter().for_each(|line| tprintln!(ctx, "{line}"));
51 }
52 Err(_) => {
53 tprintln!(ctx, "transaction not found");
54 }
55 }
56
57 return Ok(());
58 }
59 "list" => {
60 let last = if argv.is_empty() { None } else { argv[0].parse::<usize>().ok() };
61 (last, false)
62 }
63 "details" => {
64 let last = if argv.is_empty() { None } else { argv[0].parse::<usize>().ok() };
65 (last, true)
66 }
67 v => {
68 tprintln!(ctx, "unknown command: '{v}'");
69 self.display_help(ctx, argv).await?;
70 return Ok(());
71 }
72 };
73
74 let store = ctx.wallet().store().as_transaction_record_store()?;
75 let mut ids = match store.transaction_id_iter(&binding, &network_id).await {
76 Ok(ids) => ids,
77 Err(err) => {
78 if matches!(err, WalletError::NoRecordsFound) {
79 tprintln!(ctx);
80 tprintln!(ctx, "No transactions found for this account.");
81 tprintln!(ctx);
82 } else {
83 terrorln!(ctx, "{err}");
84 }
85 return Ok(());
86 }
87 };
88 let length = ids.size_hint().0;
89 let skip = if let Some(last) = last {
90 if last > length {
91 0
92 } else {
93 length - last
94 }
95 } else {
96 0
97 };
98 let mut index = 0;
99 let page = 25;
100
101 tprintln!(ctx);
102
103 while let Some(id) = ids.try_next().await? {
104 if index >= skip {
105 if index > 0 && index % page == 0 {
106 tprintln!(ctx);
107 let prompt = format!(
108 "Displaying transactions {} to {} of {} (press any key to continue, 'Q' to abort)",
109 index.separated_string(),
110 (index + page).separated_string(),
111 length.separated_string()
112 );
113 let query = ctx.term().kbhit(Some(&prompt)).await?;
114 tprintln!(ctx);
115 if query.to_lowercase() == "q" {
116 return Ok(());
117 }
118 }
119
120 match store.load_single(&binding, &network_id, &id).await {
121 Ok(tx) => {
122 let lines = tx
123 .format_transaction_with_args(
124 &ctx.wallet(),
125 None,
126 current_daa_score,
127 include_utxo,
128 true,
129 Some(account.clone()),
130 &guard,
131 )
132 .await;
133 lines.iter().for_each(|line| tprintln!(ctx, "{line}"));
134 }
135 Err(err) => {
136 terrorln!(ctx, "Unable to read transaction data: {err}");
137 }
138 }
139 }
140 index += 1;
141 }
142
143 tprintln!(ctx);
144 tprintln!(ctx, "{} transactions", length.separated_string());
145 tprintln!(ctx);
146
147 Ok(())
148 }
149
150 async fn display_help(self: Arc<Self>, ctx: Arc<KaspaCli>, _argv: Vec<String>) -> Result<()> {
151 ctx.term().help(
152 &[
153 ("list [<last N transactions>]", "List transactions"),
154 ("details [<last N transactions>]", "List transactions with UTXO details"),
155 ("lookup <transaction id>", "Lookup transaction in the history"),
156 ],
157 None,
158 )?;
159
160 Ok(())
161 }
162}