Skip to content

Commit

Permalink
refactor parent chain & coins tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
Ash-L2L committed Mar 25, 2024
1 parent 8e41610 commit dd48135
Show file tree
Hide file tree
Showing 19 changed files with 642 additions and 307 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ authors = [
"Nikita Chashchinskii <[email protected]>"
]
edition = "2021"
version = "0.5.0"
version = "0.5.1"

[workspace.dependencies.bip300301]
git = "https://github.com/Ash-L2L/bip300301.git"
rev = "c6e410e702f3d22f5801f21ffdf39edece3985df"


[profile.release]
lto = "fat"
# lto = "fat"
10 changes: 2 additions & 8 deletions app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,10 @@ impl App {
})
}

pub fn sign_and_send(&mut self) -> Result<(), Error> {
let authorized_transaction =
self.wallet.authorize(self.transaction.read().clone())?;
pub fn sign_and_send(&self, tx: Transaction) -> Result<(), Error> {
let authorized_transaction = self.wallet.authorize(tx)?;
self.runtime
.block_on(self.node.submit_transaction(&authorized_transaction))?;
*self.transaction.write() = Transaction {
inputs: vec![],
proof: Proof::default(),
outputs: vec![],
};
self.update_utxos()?;
Ok(())
}
Expand Down
42 changes: 42 additions & 0 deletions app/gui/coins/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use eframe::egui;
use strum::{EnumIter, IntoEnumIterator};

use crate::app::App;

mod tx_builder;
mod tx_creator;
mod utxo_creator;
mod utxo_selector;

use tx_builder::TxBuilder;

#[derive(Default, EnumIter, Eq, PartialEq, strum::Display)]
enum Tab {
#[default]
#[strum(to_string = "Transaction Builder")]
TransactionBuilder,
}

#[derive(Default)]
pub struct Coins {
tab: Tab,
tx_builder: TxBuilder,
}

impl Coins {
pub fn show(&mut self, app: &mut App, ui: &mut egui::Ui) {
egui::TopBottomPanel::top("coins_tabs").show(ui.ctx(), |ui| {
ui.horizontal(|ui| {
Tab::iter().for_each(|tab_variant| {
let tab_name = tab_variant.to_string();
ui.selectable_value(&mut self.tab, tab_variant, tab_name);
})
});
});
egui::CentralPanel::default().show(ui.ctx(), |ui| match self.tab {
Tab::TransactionBuilder => {
let () = self.tx_builder.show(app, ui).unwrap();
}
});
}
}
143 changes: 143 additions & 0 deletions app/gui/coins/tx_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use std::collections::HashSet;

use eframe::egui;

use thunder::{
bip300301::bitcoin,
types::{GetValue, Transaction},
};

use super::{
tx_creator::TxCreator,
utxo_creator::UtxoCreator,
utxo_selector::{show_utxo, UtxoSelector},
};
use crate::app::App;

#[derive(Debug, Default)]
pub struct TxBuilder {
// regular tx without extra data or special inputs/outputs
base_tx: Transaction,
tx_creator: TxCreator,
utxo_creator: UtxoCreator,
utxo_selector: UtxoSelector,
}

impl TxBuilder {
pub fn show_value_in(&mut self, app: &mut App, ui: &mut egui::Ui) {
ui.heading("Value In");
let selected: HashSet<_> = self
.base_tx
.inputs
.iter()
.map(|(outpoint, _)| *outpoint)
.collect();
let utxos_read = app.utxos.read();
let mut spent_utxos: Vec<_> = utxos_read
.iter()
.filter(|(outpoint, _)| selected.contains(outpoint))
.collect();
let value_in: u64 = spent_utxos
.iter()
.map(|(_, output)| output.get_value())
.sum();
self.tx_creator.value_in = value_in;
spent_utxos.sort_by_key(|(outpoint, _)| format!("{outpoint}"));
ui.separator();
ui.monospace(format!("Total: {}", bitcoin::Amount::from_sat(value_in)));
ui.separator();
egui::Grid::new("utxos").striped(true).show(ui, |ui| {
ui.monospace("kind");
ui.monospace("outpoint");
ui.monospace("value");
ui.end_row();
let mut remove = None;
for (vout, (outpoint, _)) in self.base_tx.inputs.iter().enumerate()
{
let output = &utxos_read[outpoint];
show_utxo(ui, outpoint, output);
if ui.button("remove").clicked() {
remove = Some(vout);
}
ui.end_row();
}
if let Some(vout) = remove {
self.base_tx.inputs.remove(vout);
}
});
}

pub fn show_value_out(&mut self, ui: &mut egui::Ui) {
ui.heading("Value Out");
ui.separator();
let value_out: u64 =
self.base_tx.outputs.iter().map(GetValue::get_value).sum();
self.tx_creator.value_out = value_out;
ui.monospace(format!(
"Total: {}",
bitcoin::Amount::from_sat(value_out)
));
ui.separator();
egui::Grid::new("outputs").striped(true).show(ui, |ui| {
let mut remove = None;
ui.monospace("vout");
ui.monospace("address");
ui.monospace("value");
ui.end_row();
for (vout, output) in self.base_tx.outputs.iter().enumerate() {
let address = &format!("{}", output.address)[0..8];
let value = bitcoin::Amount::from_sat(output.get_value());
ui.monospace(format!("{vout}"));
ui.monospace(address.to_string());
ui.with_layout(
egui::Layout::right_to_left(egui::Align::Max),
|ui| {
ui.monospace(format!("{value}"));
},
);
if ui.button("remove").clicked() {
remove = Some(vout);
}
ui.end_row();
}
if let Some(vout) = remove {
self.base_tx.outputs.remove(vout);
}
});
}

pub fn show(
&mut self,
app: &mut App,
ui: &mut egui::Ui,
) -> anyhow::Result<()> {
egui::SidePanel::left("spend_utxo")
.exact_width(250.)
.resizable(false)
.show_inside(ui, |ui| {
self.utxo_selector.show(app, ui, &mut self.base_tx);
});
egui::SidePanel::left("value_in")
.exact_width(250.)
.resizable(false)
.show_inside(ui, |ui| {
let () = self.show_value_in(app, ui);
});
egui::SidePanel::left("value_out")
.exact_width(250.)
.resizable(false)
.show_inside(ui, |ui| {
let () = self.show_value_out(ui);
});
egui::SidePanel::left("create_utxo")
.exact_width(450.)
.resizable(false)
.show_separator_line(false)
.show_inside(ui, |ui| {
self.utxo_creator.show(app, ui, &mut self.base_tx);
ui.separator();
self.tx_creator.show(app, ui, &mut self.base_tx).unwrap();
});
Ok(())
}
}
68 changes: 68 additions & 0 deletions app/gui/coins/tx_creator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use eframe::egui;

use thunder::{
bip300301::bitcoin,
types::{Transaction, Txid},
};

use crate::app::App;

#[derive(Debug, Default)]
pub struct TxCreator {
pub value_in: u64,
pub value_out: u64,
// if the base tx has changed, need to recompute final tx
base_txid: Txid,
final_tx: Option<Transaction>,
}

fn send_tx(app: &App, tx: &mut Transaction) -> anyhow::Result<()> {
app.node.regenerate_proof(tx)?;
let () = app.sign_and_send(tx.clone())?;
Ok(())
}

impl TxCreator {
pub fn show(
&mut self,
app: &mut App,
ui: &mut egui::Ui,
base_tx: &mut Transaction,
) -> anyhow::Result<()> {
// if base txid has changed, store the new txid
let base_txid = base_tx.txid();
let base_txid_changed = base_txid != self.base_txid;
if base_txid_changed {
self.base_txid = base_txid;
}
// (re)compute final tx if:
// * the tx type, tx data, or base txid has changed
// * final tx not yet set
let refresh_final_tx = base_txid_changed || self.final_tx.is_none();
if refresh_final_tx {
self.final_tx = Some(base_tx.clone());
}
let final_tx = match &mut self.final_tx {
None => panic!("impossible! final tx should have been set"),
Some(final_tx) => final_tx,
};
let txid = &format!("{}", final_tx.txid())[0..8];
ui.monospace(format!("txid: {txid}"));
if self.value_in >= self.value_out {
let fee = self.value_in - self.value_out;
let fee = bitcoin::Amount::from_sat(fee);
ui.monospace(format!("fee: {fee}"));
if ui.button("sign and send").clicked() {
if let Err(err) = send_tx(app, final_tx) {
tracing::error!("{err:#}");
} else {
*base_tx = Transaction::default();
self.final_tx = None;
}
}
} else {
ui.label("Not Enough Value In");
}
Ok(())
}
}
32 changes: 19 additions & 13 deletions app/gui/utxo_creator.rs → app/gui/coins/utxo_creator.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
use eframe::egui;
use thunder::{
bip300301::bitcoin,
types::{self, Output, OutputContent},
types::{self, Output, OutputContent, Transaction},
};

use crate::app::App;

pub struct UtxoCreator {
utxo_type: UtxoType,
value: String,
address: String,
main_address: String,
main_fee: String,
}

#[derive(Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
enum UtxoType {
Regular,
Withdrawal,
Expand All @@ -29,6 +21,15 @@ impl std::fmt::Display for UtxoType {
}
}

#[derive(Debug)]
pub struct UtxoCreator {
utxo_type: UtxoType,
value: String,
address: String,
main_address: String,
main_fee: String,
}

impl Default for UtxoCreator {
fn default() -> Self {
Self {
Expand All @@ -42,7 +43,12 @@ impl Default for UtxoCreator {
}

impl UtxoCreator {
pub fn show(&mut self, app: &mut App, ui: &mut egui::Ui) {
pub fn show(
&mut self,
app: &mut App,
ui: &mut egui::Ui,
tx: &mut Transaction,
) {
ui.horizontal(|ui| {
ui.heading("Create");
egui::ComboBox::from_id_source("utxo_type")
Expand Down Expand Up @@ -124,7 +130,7 @@ impl UtxoCreator {
value.expect("should not happen").to_sat(),
),
};
app.transaction.write().outputs.push(utxo);
tx.outputs.push(utxo);
}
}
UtxoType::Withdrawal => {
Expand Down Expand Up @@ -166,7 +172,7 @@ impl UtxoCreator {
.to_sat(),
},
};
app.transaction.write().outputs.push(utxo);
tx.outputs.push(utxo);
}
}
}
Expand Down
Loading

0 comments on commit dd48135

Please sign in to comment.