Skip to content

Commit 1d2db3c

Browse files
committedJan 6, 2022
new commit
1 parent a2b4d14 commit 1d2db3c

File tree

1 file changed

+308
-141
lines changed

1 file changed

+308
-141
lines changed
 

‎src/main.rs

+308-141
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use bdk::blockchain::ElectrumBlockchain;
55
use bdk::database::MemoryDatabase;
66
use bdk::electrum_client::ElectrumApi;
77
use bdk::wallet::AddressIndex;
8-
use iced::{button,text_input, Application, executor, Command, Clipboard, Element, Text, Settings, TextInput, Length, Column, Button, Scrollable, Container, scrollable};
8+
use iced::{button,text_input, Application, executor, Command, Clipboard, Element, Text, Settings, TextInput, Length, Column, Button, Scrollable, Container, scrollable, Row, Align, window};
99
use iced::HorizontalAlignment;
1010

1111

@@ -19,7 +19,13 @@ mod test_electrum;
1919

2020
pub fn main() -> iced::Result {
2121

22-
RuWallet::run(Settings::default())
22+
RuWallet::run(Settings {
23+
window: window::Settings {
24+
size: (1600, 768),
25+
..window::Settings::default()
26+
},
27+
..Settings::default()
28+
})
2329
}
2430

2531
/*
@@ -30,6 +36,29 @@ struct RWallet {
3036
}
3137
3238
*/
39+
#[derive(Debug, Default)]
40+
struct AddressRow {
41+
index: u64,
42+
address: String,
43+
balance: u64,
44+
tx_count: u64
45+
}
46+
47+
#[derive(Debug, Default)]
48+
struct UTXORow {
49+
txid: String,
50+
vout: u32,
51+
address: String,
52+
amount: u64,
53+
height: u32
54+
}
55+
56+
#[derive(Debug, Default, Clone)]
57+
struct TransactionRow {
58+
txid: String,
59+
amount: i128,
60+
height: u32
61+
}
3362

3463
#[derive(Debug, Default)]
3564
struct RuWallet{
@@ -43,13 +72,13 @@ struct RuWallet{
4372

4473
create_wallet_button_state: button::State,
4574

46-
address_items: Vec<String>,
47-
4875
new_address: String,
4976

50-
utxo_items: Vec<String>,
77+
address_items: Vec<AddressRow>,
78+
79+
utxo_items: Vec<UTXORow>,
5180

52-
transaction_items: Vec<String>
81+
transaction_items: Vec<TransactionRow>
5382
}
5483

5584
#[derive(Debug, Clone)]
@@ -69,7 +98,7 @@ impl Application for RuWallet {
6998
}
7099

71100
fn title(&self) -> String {
72-
String::from("A cool application")
101+
String::from("Rust Wallet")
73102
}
74103

75104
fn update(&mut self, _message: Self::Message, _clipboard: &mut Clipboard) -> Command<Self::Message> {
@@ -81,57 +110,64 @@ impl Application for RuWallet {
81110
self.internal_descriptor_input_value = value.clone();
82111
},
83112
RuWalletMessage::CreateWallet => {
84-
println!("{}", "Generating wallet ...");
113+
println!("{}", "Restoring wallet ...");
85114

86115
self.address_items.clear();
87116
self.new_address.clear();
88117
self.utxo_items.clear();
118+
self.transaction_items.clear();
89119

90120
let wallet = block_on(self.generate_wallet());
91121

92122
self.address_items = block_on(self.get_external_addresses(&wallet));
93123

94124
self.new_address = wallet.get_address(AddressIndex::New).unwrap().address.to_string();
95125

96-
for utxo in wallet.list_unspent().unwrap().iter() {
97-
98-
let addr = Address::from_script(&utxo.txout.script_pubkey, Network::Testnet).unwrap();
99-
100-
self.utxo_items.push(
101-
format!("{}:{} - {} - {} sats", utxo.outpoint.txid, utxo.outpoint.vout, addr.to_string(), utxo.txout.value)
102-
);
103-
}
104-
105126
let mut tx_list = wallet.list_transactions(true).unwrap();
106127

107128
tx_list.sort_by(|a, b|
108129
b.confirmation_time.as_ref().unwrap().height.cmp(&a.confirmation_time.as_ref().unwrap().height));
109130

110131
for tx in tx_list.iter() {
111132

112-
let mut amount_i64: Option<i64> = None;
113-
let mut amount_u64:Option<u64> = None;
133+
let height = tx.confirmation_time.as_ref().unwrap().height;
114134

115-
let x= tx.received.overflowing_sub(tx.sent);
135+
let amount = tx.received as i128 - tx.sent as i128;
116136

117-
let height = tx.confirmation_time.as_ref().unwrap().height;
137+
self.transaction_items.push(
138+
TransactionRow {
139+
txid: tx.txid.to_string(),
140+
amount,
141+
height
142+
}
143+
);
144+
}
145+
146+
for utxo in wallet.list_unspent().unwrap().iter() {
147+
148+
let addr = Address::from_script(&utxo.txout.script_pubkey, Network::Testnet).unwrap();
149+
150+
let utxo_tx = (&mut self.transaction_items).iter_mut().find(
151+
|tr| tr.txid.to_string().eq(&utxo.outpoint.txid.to_string())
152+
);
153+
154+
let height = match utxo_tx {
155+
Some(tr) => tr.height,
156+
None => 0,
157+
};
118158

119-
if x.1 {
120-
amount_i64 = Some(x.0 as i64);
121-
} else {
122-
amount_u64 = Some(x.0);
123-
}
124-
125-
if let Some(i) = amount_u64 {
126-
self.transaction_items.push(
127-
format!("{} - amount: {} sats - height: {}", tx.txid, i, height)
128-
);
129-
} else if let Some(i) = amount_i64 {
130-
self.transaction_items.push(
131-
format!("{} - amount: {} sats - height: {}", tx.txid, i, height)
132-
);
133-
}
159+
self.utxo_items.push(
160+
UTXORow {
161+
txid: utxo.outpoint.txid.to_string(),
162+
vout: utxo.outpoint.vout,
163+
address: addr.to_string(),
164+
amount: utxo.txout.value,
165+
height
166+
}
167+
)
134168
}
169+
170+
self.utxo_items.sort_by(|a, b| b.height.cmp(&a.height));
135171
},
136172
}
137173

@@ -153,8 +189,8 @@ impl Application for RuWallet {
153189
Self::Message::ExternalDescriptorInputChanged
154190
)
155191
.padding(15)
156-
.size(30)
157-
.on_submit(Self::Message::CreateWallet);
192+
.size(30);
193+
//.on_submit(Self::Message::CreateWallet);
158194

159195
let internal_descriptor_input = TextInput::new(
160196
&mut self.internal_descriptor_input_state,
@@ -163,56 +199,126 @@ impl Application for RuWallet {
163199
Self::Message::InternalDescriptorInputChanged
164200
)
165201
.padding(15)
166-
.size(30)
167-
.on_submit(Self::Message::CreateWallet);
202+
.size(30);
203+
//.on_submit(Self::Message::CreateWallet);
168204

169205
let create_wallet_button = Button::new(
170206
&mut self.create_wallet_button_state,
171-
Text::new("Generate Wallet")
207+
Text::new("Restore Wallet")
172208
)
173209
.padding(15)
174210
.on_press(Self::Message::CreateWallet);
175211

176212
let mut content = Column::new()
177-
.max_width(800)
178213
.spacing(20)
179214
.push(title)
180215
.push(external_descriptor_input)
181216
.push(internal_descriptor_input)
182217
.push(create_wallet_button);
183218

184-
185-
// show used addresses
186219
if !self.address_items.is_empty() {
187220

188-
let used_addresses_title = Text::new("Address List")
221+
let address_list_title = Text::new("Address List")
189222
.width(Length::Fill)
190223
.size(45)
191224
.color([0.5, 0.5, 0.5])
192225
.horizontal_alignment(HorizontalAlignment::Left);
193226

194-
let used_address_list = self.address_items
195-
.iter()
196-
.enumerate()
197-
.fold(Column::new().spacing(20), |column, (_i, address_item)| {
198-
let address_text = Text::new(address_item)
199-
.width(Length::Fill)
227+
let mut address_table: Column<RuWalletMessage> = Column::new()
228+
.width(iced::Length::FillPortion(1000))
229+
.spacing(30);
230+
231+
232+
let mut table_header: Row<RuWalletMessage> = Row::new()
233+
.align_items(Align::Start)
234+
.spacing(20);
235+
236+
table_header = table_header
237+
.push(
238+
Text::new("Index")
239+
.width(Length::Units(50))
240+
.size(20)
241+
.horizontal_alignment(HorizontalAlignment::Left)
242+
)
243+
.push(
244+
Text::new("Type")
245+
.width(Length::Units(110))
200246
.size(20)
201-
.color([0.5, 0.5, 0.5])
202-
.horizontal_alignment(HorizontalAlignment::Left);
247+
.horizontal_alignment(HorizontalAlignment::Left)
248+
)
249+
.push(
250+
Text::new("Address")
251+
.width(Length::Units(510))
252+
.size(20)
253+
.horizontal_alignment(HorizontalAlignment::Left)
254+
)
255+
.push(
256+
Text::new("Balance (sats)")
257+
.width(Length::Units(150))
258+
.size(20)
259+
.horizontal_alignment(HorizontalAlignment::Left)
260+
)
261+
.push(
262+
Text::new("Tx Count")
263+
.width(Length::Units(90))
264+
.size(20)
265+
.horizontal_alignment(HorizontalAlignment::Left)
266+
);
267+
268+
address_table = address_table.push(table_header);
269+
270+
271+
for addr_item in &self.address_items {
272+
273+
let mut table_row = Row::new()
274+
.align_items(Align::Start)
275+
.spacing(20);
203276

204-
column.push(address_text)
205-
});
277+
let addr_index_text = Text::new(addr_item.index.to_string())
278+
.width(Length::Units(50))
279+
.size(20)
280+
.horizontal_alignment(HorizontalAlignment::Left);
281+
282+
let addr_type_text = Text::new("receiving")
283+
.width(Length::Units(110))
284+
.size(20)
285+
.horizontal_alignment(HorizontalAlignment::Left);
286+
287+
let addr_text = Text::new(addr_item.address.to_string())
288+
.width(Length::Units(510))
289+
.size(20)
290+
.horizontal_alignment(HorizontalAlignment::Left);
291+
292+
let addr_balance_text = Text::new(addr_item.balance.to_string())
293+
.width(Length::Units(150))
294+
.size(20)
295+
.horizontal_alignment(HorizontalAlignment::Right);
296+
297+
let addr_tx_count_text = Text::new(addr_item.tx_count.to_string())
298+
.width(Length::Units(90))
299+
.size(20)
300+
.horizontal_alignment(HorizontalAlignment::Right);
301+
302+
table_row = table_row
303+
.push(addr_index_text)
304+
.push(addr_type_text)
305+
.push(addr_text)
306+
.push(addr_balance_text)
307+
.push(addr_tx_count_text);
308+
309+
address_table = address_table.push(table_row);
310+
311+
}
206312

207313
content = content
208-
.push(used_addresses_title)
209-
.push(used_address_list);
314+
.push(address_list_title)
315+
.push(address_table);
210316
}
211317

212318
// show new address
213319
if !self.new_address.is_empty() {
214320

215-
let new_address_title = Text::new("New Address")
321+
let new_address_title = Text::new("Current Receive Address")
216322
.width(Length::Fill)
217323
.size(45)
218324
.color([0.5, 0.5, 0.5])
@@ -221,15 +327,13 @@ impl Application for RuWallet {
221327
let new_address_text =Text::new(&self.new_address)
222328
.width(Length::Fill)
223329
.size(20)
224-
.color([0.5, 0.5, 0.5])
225330
.horizontal_alignment(HorizontalAlignment::Left);
226331

227332
content = content
228333
.push(new_address_title)
229334
.push(new_address_text);
230335
}
231336

232-
// show UTXO list
233337
if !self.utxo_items.is_empty() {
234338

235339
let unspent_list_title = Text::new("Unspent List")
@@ -238,61 +342,164 @@ impl Application for RuWallet {
238342
.color([0.5, 0.5, 0.5])
239343
.horizontal_alignment(HorizontalAlignment::Left);
240344

241-
let unspent_list = self.utxo_items
242-
.iter()
243-
.enumerate()
244-
.fold(Column::new().spacing(20), |column, (_i, utxo_item)| {
245-
let utxo_text = Text::new(utxo_item)
246-
.width(Length::Fill)
345+
let mut unspent_table: Column<RuWalletMessage> = Column::new()
346+
.width(iced::Length::Fill)
347+
.spacing(30);
348+
349+
let mut table_header: Row<RuWalletMessage> = Row::new()
350+
.align_items(Align::Start)
351+
.spacing(20);
352+
353+
table_header = table_header
354+
.push(
355+
Text::new("Output Point")
356+
.width(Length::Units(710))
357+
.size(20)
358+
.horizontal_alignment(HorizontalAlignment::Left)
359+
)
360+
.push(
361+
Text::new("Address")
362+
.width(Length::Units(510))
363+
.size(20)
364+
.horizontal_alignment(HorizontalAlignment::Left)
365+
)
366+
.push(
367+
Text::new("Amount (sats)")
368+
.width(Length::Units(150))
369+
.size(20)
370+
.horizontal_alignment(HorizontalAlignment::Left)
371+
)
372+
.push(
373+
Text::new("Height")
374+
.width(Length::Units(110))
247375
.size(20)
248-
.color([0.5, 0.5, 0.5])
249-
.horizontal_alignment(HorizontalAlignment::Left);
376+
.horizontal_alignment(HorizontalAlignment::Left)
377+
);
250378

251-
column.push(utxo_text)
252-
});
379+
unspent_table = unspent_table.push(table_header);
380+
381+
for utxo_item in &self.utxo_items {
382+
383+
let mut table_row: Row<RuWalletMessage> = Row::new()
384+
.align_items(Align::Start)
385+
.spacing(20);
386+
387+
let txid_vout = format!("{}:{}", utxo_item.txid.to_string(), utxo_item.vout);
388+
389+
let txid_text = Text::new(txid_vout)
390+
.width(Length::Units(710))
391+
.size(20)
392+
.horizontal_alignment(HorizontalAlignment::Left);
393+
394+
let address_text = Text::new(&utxo_item.address)
395+
.width(Length::Units(510))
396+
.size(20)
397+
.horizontal_alignment(HorizontalAlignment::Left);
398+
399+
let address_amount = Text::new(utxo_item.amount.to_string())
400+
.width(Length::Units(150))
401+
.size(20)
402+
.horizontal_alignment(HorizontalAlignment::Right);
403+
404+
let height = Text::new(utxo_item.height.to_string())
405+
.width(Length::Units(110))
406+
.size(20)
407+
.horizontal_alignment(HorizontalAlignment::Right);
408+
409+
table_row = table_row
410+
.push(txid_text)
411+
.push(address_text)
412+
.push(address_amount)
413+
.push(height);
414+
415+
unspent_table = unspent_table.push(table_row);
416+
}
253417

254418
content = content
255419
.push(unspent_list_title)
256-
.push(unspent_list);
420+
.push(unspent_table);
257421
}
258422

259-
// show transaction list
260-
if !self.utxo_items.is_empty() {
423+
if !self.transaction_items.is_empty() {
261424

262425
let tx_list_title = Text::new("Transaction List")
263426
.width(Length::Fill)
264427
.size(45)
265428
.color([0.5, 0.5, 0.5])
266429
.horizontal_alignment(HorizontalAlignment::Left);
267430

268-
let tx_list = self.transaction_items
269-
.iter()
270-
.enumerate()
271-
.fold(Column::new().spacing(20), |column, (_i, tx_item)| {
272-
let tx_text = Text::new(tx_item)
273-
.width(Length::Fill)
431+
let mut transaaction_table: Column<RuWalletMessage> = Column::new()
432+
.width(iced::Length::Fill)
433+
.spacing(30);
434+
435+
let mut table_header: Row<RuWalletMessage> = Row::new()
436+
.align_items(Align::Start)
437+
.spacing(20);
438+
439+
table_header = table_header
440+
.push(
441+
Text::new("Transaction Id")
442+
.width(Length::Units(710))
443+
.size(20)
444+
.horizontal_alignment(HorizontalAlignment::Left)
445+
)
446+
.push(
447+
Text::new("Amount (sats)")
448+
.width(Length::Units(150))
449+
.size(20)
450+
.horizontal_alignment(HorizontalAlignment::Left)
451+
)
452+
.push(
453+
Text::new("Height")
454+
.width(Length::Units(110))
274455
.size(20)
275-
.color([0.5, 0.5, 0.5])
276-
.horizontal_alignment(HorizontalAlignment::Left);
456+
.horizontal_alignment(HorizontalAlignment::Left)
457+
);
277458

278-
column.push(tx_text)
279-
});
459+
transaaction_table = transaaction_table.push(table_header);
460+
461+
for transaction_item in &self.transaction_items {
462+
463+
let mut table_row: Row<RuWalletMessage> = Row::new()
464+
.align_items(Align::Start)
465+
.spacing(20);
466+
467+
let txid_text = Text::new(&transaction_item.txid)
468+
.width(Length::Units(710))
469+
.size(20)
470+
.horizontal_alignment(HorizontalAlignment::Left);
471+
472+
let amount_text = Text::new(transaction_item.amount.to_string())
473+
.width(Length::Units(150))
474+
.size(20)
475+
.horizontal_alignment(HorizontalAlignment::Right);
476+
477+
let height_amount = Text::new(transaction_item.height.to_string())
478+
.width(Length::Units(110))
479+
.size(20)
480+
.horizontal_alignment(HorizontalAlignment::Right);
481+
482+
table_row = table_row
483+
.push(txid_text)
484+
.push(amount_text)
485+
.push(height_amount);
486+
487+
transaaction_table = transaaction_table.push(table_row);
488+
}
280489

281490
content = content
282491
.push(tx_list_title)
283-
.push(tx_list);
492+
.push(transaaction_table);
284493
}
285494

286-
287495
Scrollable::new(&mut self.scroll)
288496
.padding(40)
497+
.width(Length::Units(13400))
289498
.push(
290499
Container::new(content).width(Length::Fill).center_x(),
291500
)
292501
.into()
293502
}
294-
295-
296503
}
297504

298505
impl RuWallet {
@@ -307,19 +514,19 @@ impl RuWallet {
307514
let wallet = w_electrum::load_or_create_wallet(electrum_url,
308515
&network,
309516
&self.external_descriptor_input_value,
310-
&self.internal_descriptor_input_value,
311-
);
517+
&self.internal_descriptor_input_value
518+
);
312519

313520
wallet
314521
}
315522

316-
async fn get_external_addresses(&self, wallet: &Wallet<ElectrumBlockchain, MemoryDatabase>) -> Vec::<String> {
523+
async fn get_external_addresses(&self, wallet: &Wallet<ElectrumBlockchain, MemoryDatabase>) -> Vec::<AddressRow> {
317524

318525
let electrum_url = "ssl://electrum.blockstream.info:60002";
319526

320527
let mut scripts = Vec::<Script>::new();
321528

322-
for n in 0..30 {
529+
for n in 0..10 {
323530
let address_info = wallet.get_address(AddressIndex::Peek(n)).unwrap();
324531

325532
scripts.push(address_info.script_pubkey());
@@ -328,59 +535,19 @@ impl RuWallet {
328535
let additional_addr_info =
329536
w_electrum::get_batch_history_and_balance(electrum_url, &scripts);
330537

331-
let mut result = Vec::<String>::new();
538+
let mut result = Vec::<AddressRow>::new();
332539

333540
for aai in additional_addr_info {
334-
println!("{} {}: {} txs - {} sats", aai.index, aai.address, aai.tx_count, aai.balance);
335-
result.push(format!("{} {}: {} txs - {} sats", aai.index, aai.address, aai.tx_count, aai.balance));
541+
result.push(
542+
AddressRow {
543+
index: aai.index,
544+
address: aai.address,
545+
balance: aai.balance,
546+
tx_count: aai.tx_count
547+
}
548+
);
336549
}
337550

338551
result
339552
}
340-
}
341-
342-
// Move to other file later
343-
/*
344-
#[derive(Debug, Clone)]
345-
struct AddressItem {
346-
address: String
347-
}
348-
349-
struct AddressItemMessage;
350-
351-
impl AddressItem {
352-
fn new(val: String) -> Self {
353-
AddressItem { address: val }
354-
}
355-
356-
fn update(&mut self, _message: AddressItemMessage) { }
357-
358-
fn view(&mut self) -> Element<AddressItemMessage> {
359-
let address = Text::new("R Wallet")
360-
.width(Length::Fill)
361-
.size(30)
362-
.color([0.5, 0.5, 0.5])
363-
.horizontal_alignment(HorizontalAlignment::Center);
364-
365-
address.into()
366-
}
367-
}
368-
*/
369-
370-
/*
371-
fn new(_flags: ()) -> (Hello, Command<Self::Message>) {
372-
(Hello, Command::none())
373-
}
374-
375-
fn title(&self) -> String {
376-
String::from("A cool application")
377-
}
378-
379-
fn update(&mut self, _message: Self::Message) -> Command<Self::Message> {
380-
Command::none()
381-
}
382-
383-
fn view(&mut self) -> Element<Self::Message> {
384-
Text::new("Hello, world!").into()
385-
}
386-
*/
553+
}

0 commit comments

Comments
 (0)
Please sign in to comment.