Skip to content
This repository has been archived by the owner on Sep 6, 2024. It is now read-only.

Commit

Permalink
[+] add send transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
heng30 committed Dec 30, 2023
1 parent 93fdb5f commit 61b89dc
Show file tree
Hide file tree
Showing 21 changed files with 234 additions and 100 deletions.
2 changes: 1 addition & 1 deletion bitbox/src/btc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ mod tests {
#[tokio::test]
async fn test_price() -> Result<()> {
let price = super::price().await?;
assert!(price > 0);
assert!(price > 0_f64);

println!("{}", price);
Ok(())
Expand Down
3 changes: 3 additions & 0 deletions bitbox/src/logic/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ fn load_items(ui: Weak<AppWindow>) {
value["test-address"].as_str().unwrap().to_string()
};

super::activity::load_items(ui.clone(), network.clone());
super::address_book::load_items(ui.clone(), network.clone());

let _ = slint::invoke_from_event_loop(move || {
let ui = ui.clone().unwrap();

Expand Down
3 changes: 0 additions & 3 deletions bitbox/src/logic/activity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ use tokio::task::spawn;
use uuid::Uuid;

pub fn init(ui: &AppWindow) {
let account = ui.global::<Store>().get_account();
load_items(ui.as_weak(), account.network.to_string());

let ui_handle = ui.as_weak();
ui.global::<Logic>().on_activity_delete_item(move |uuid| {
let ui = ui_handle.unwrap();
Expand Down
3 changes: 0 additions & 3 deletions bitbox/src/logic/address_book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ use tokio::task::spawn;
use uuid::Uuid;

pub fn init(ui: &AppWindow) {
let account = ui.global::<Store>().get_account();
load_items(ui.as_weak(), account.network.to_string());

let ui_handle = ui.as_weak();
ui.global::<Logic>().on_set_receive_address(move |address| {
ui_handle.unwrap().set_receive_address(address);
Expand Down
169 changes: 90 additions & 79 deletions bitbox/src/logic/btcinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ use crate::wallet::transaction::blockstream;
use crate::{btc, db, util};
use serde_json::Value;
use slint::{ComponentHandle, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use tokio::task::spawn;
use tokio::time::{sleep, Duration};

static IS_FLUSH_NOW: AtomicBool = AtomicBool::new(false);

pub fn init(ui: &AppWindow) {
update_timer(ui.as_weak());

Expand All @@ -22,104 +25,112 @@ pub fn init(ui: &AppWindow) {
slint::format!("{:.8}", price)
}
});

ui.global::<Logic>().on_flush_account(move || {
IS_FLUSH_NOW.store(true, Ordering::SeqCst);
});
}

fn update_timer(ui: Weak<AppWindow>) {
spawn(async move {
const FLUSH_INTERVAL: u64 = 60_u64;
let mut inc_index = 0_u64;

loop {
let (network, address) = match db::account::select_all().await {
Ok(items) => {
if items.is_empty() {
(None, None)
} else {
match serde_json::from_str::<Value>(&items[0].data) {
Err(e) => {
log::warn!("Error: {e:?}");
(None, None)
}
Ok(value) => {
let network = value["network"].as_str().unwrap().to_string();
let address = if network == "main" {
value["main-address"].as_str().unwrap().to_string()
} else {
value["test-address"].as_str().unwrap().to_string()
};

(Some(network), Some(address))
if inc_index % FLUSH_INTERVAL == 0 || IS_FLUSH_NOW.load(Ordering::SeqCst) {
let (network, address) = match db::account::select_all().await {
Ok(items) => {
if items.is_empty() {
(None, None)
} else {
match serde_json::from_str::<Value>(&items[0].data) {
Err(e) => {
log::warn!("Error: {e:?}");
(None, None)
}
Ok(value) => {
let network = value["network"].as_str().unwrap().to_string();
let address = if network == "main" {
value["main-address"].as_str().unwrap().to_string()
} else {
value["test-address"].as_str().unwrap().to_string()
};

(Some(network), Some(address))
}
}
}
}
}
Err(e) => {
log::warn!("Error: {}", e);
(None, None)
}
};

if network.is_none() || address.is_none() {
sleep(Duration::from_secs(10)).await;
continue;
}

let (network, address) = (network.unwrap(), address.unwrap());
let balance = match blockstream::fetch_balance(&network, &address).await {
Err(e) => {
log::warn!("{:?}", e);
None
}
Ok(value) => Some(value as f64 / 10e8),
};
Err(e) => {
log::warn!("Error: {}", e);
(None, None)
}
};

if network.is_some() && address.is_some() {
let (network, address) = (network.unwrap(), address.unwrap());
let balance = match blockstream::fetch_balance(&network, &address).await {
Err(e) => {
log::warn!("{:?}", e);
None
}
Ok(value) => Some(value as f64 / 1e8),
};

let price = match btc::price().await {
Err(e) => {
log::warn!("{:?}", e);
0_u64
}
Ok(value) => value as u64,
};
let price = match btc::price().await {
Err(e) => {
log::warn!("{:?}", e);
0_u64
}
Ok(value) => value as u64,
};

let (slow, normal, fast) = match btc::feerate().await {
Err(e) => {
log::warn!("{:?}", e);
(0_u64, 0_u64, 0_u64)
}
Ok(item) => item,
};
let (slow, normal, fast) = match btc::feerate().await {
Err(e) => {
log::warn!("{:?}", e);
(0_u64, 0_u64, 0_u64)
}
Ok(item) => item,
};

let ui = ui.clone();
let _ = slint::invoke_from_event_loop(move || {
let ui = ui.unwrap();
let mut info = ui.global::<Store>().get_btc_info();
let ui = ui.clone();
let _ = slint::invoke_from_event_loop(move || {
let ui = ui.unwrap();
let mut info = ui.global::<Store>().get_btc_info();

if price > 0 {
info.price = slint::format!("{}", price);
}
if price > 0 {
info.price = slint::format!("{}", price);
}

if slow > 0 {
info.byte_fee_slow = slint::format!("{}", slow);
info.byte_fee_normal = slint::format!("{}", normal);
info.byte_fee_fast = slint::format!("{}", fast);
}
info.update_time = util::time::local_now("%H:%M:%S").into();
ui.global::<Store>().set_btc_info(info);
if slow > 0 {
info.byte_fee_slow = slint::format!("{}", slow);
info.byte_fee_normal = slint::format!("{}", normal);
info.byte_fee_fast = slint::format!("{}", fast);
}
info.update_time = util::time::local_now("%H:%M:%S").into();
ui.global::<Store>().set_btc_info(info);

let mut account = ui.global::<Store>().get_account();
let mut account = ui.global::<Store>().get_account();

if balance.is_some() {
account.balance_btc = slint::format!("{}", balance.unwrap());
}
if balance.is_some() {
account.balance_btc = slint::format!("{}", balance.unwrap());
}

if price > 0 {
let btc_amount: f64 = account.balance_btc.parse().unwrap_or(0_f64);
account.balance_usd = slint::format!("{:.2}", (btc_amount * price as f64));
}
if price > 0 {
let btc_amount: f64 = account.balance_btc.parse().unwrap_or(0_f64);
account.balance_usd =
slint::format!("{:.2}", (btc_amount * price as f64));
}

if balance.is_some() || price > 0 {
ui.global::<Store>().set_account(account);
if balance.is_some() || price > 0 {
ui.global::<Store>().set_account(account);
}
});
}
});
}

sleep(Duration::from_secs(60)).await;
inc_index += 1;
sleep(Duration::from_secs(1)).await;
}
});
}
1 change: 1 addition & 0 deletions bitbox/src/logic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ pub mod setting;
pub mod util;
pub mod window;
pub mod account;
pub mod send_tx;

pub use message::*;

Check warning on line 16 in bitbox/src/logic/mod.rs

View workflow job for this annotation

GitHub Actions / action-run

unused import: `message::*`
8 changes: 8 additions & 0 deletions bitbox/src/logic/password_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ pub fn init(ui: &AppWindow) {
ui.global::<Logic>()
.invoke_recover_account(handle_uuid, password);
}
"send-tx" => {
let receive_address = ui.get_receive_address();
let send_amount = ui.get_send_amount();
let feerate = ui.get_feerate();

ui.global::<Logic>()
.invoke_send_tx(handle_uuid, password, receive_address, send_amount, feerate);
}
"logout" => {
handle_logout(ui.as_weak(), handle_uuid.to_string(), password.to_string());
}
Expand Down
91 changes: 91 additions & 0 deletions bitbox/src/logic/send_tx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use crate::config;
use crate::db;
use crate::message::{async_message_success, async_message_warn};

Check warning on line 3 in bitbox/src/logic/send_tx.rs

View workflow job for this annotation

GitHub Actions / action-run

unused import: `async_message_success`
use crate::password_dialog::is_password_verify;
use crate::slint_generatedAppWindow::{AddressBookItem, AppWindow, Logic, Store};

Check warning on line 5 in bitbox/src/logic/send_tx.rs

View workflow job for this annotation

GitHub Actions / action-run

unused imports: `AddressBookItem`, `Store`
use crate::util::translator::tr;
use crate::wallet::{
account::{address, sendinfo, tx},
transaction::blockstream,

Check warning on line 9 in bitbox/src/logic/send_tx.rs

View workflow job for this annotation

GitHub Actions / action-run

unused import: `transaction::blockstream`
};
use crate::{message_success, message_warn};

Check warning on line 11 in bitbox/src/logic/send_tx.rs

View workflow job for this annotation

GitHub Actions / action-run

unused import: `message_success`
use serde_json::Value;
use slint::{ComponentHandle, Weak};

Check warning on line 13 in bitbox/src/logic/send_tx.rs

View workflow job for this annotation

GitHub Actions / action-run

unused import: `Weak`
use tokio::task::spawn;
use uuid::Uuid;

Check warning on line 15 in bitbox/src/logic/send_tx.rs

View workflow job for this annotation

GitHub Actions / action-run

unused import: `uuid::Uuid`

pub fn init(ui: &AppWindow) {
let ui_handle = ui.as_weak();
ui.global::<Logic>().on_send_tx(
move |uuid, password, receive_address, send_amount, feerate| {
let ui = ui_handle.unwrap();
let uuid = uuid.to_string();
let password = password.to_string();
let receive_address = receive_address.to_string();
let send_amount = send_amount.to_string();
let feerate = feerate.to_string();

if receive_address.is_empty() || send_amount.is_empty() || feerate.is_empty() {
message_warn!(ui, tr("非法输入"));
return;
}

let ui = ui.as_weak();
spawn(async move {
if !is_password_verify(uuid.clone(), password.clone()).await {
async_message_warn(ui.clone(), tr("密码错误"));
return;
}

match db::account::select(&uuid).await {
Ok(account) => match serde_json::from_str::<Value>(&account.data) {
Err(e) => async_message_warn(
ui.clone(),
format!("{}. {}: {e:?}", tr("生成交易失败"), tr("原因")),
),
Ok(value) => {
let address_info = address::Info {
uuid: value["uuid"].as_str().unwrap().to_string(),
name: value["name"].as_str().unwrap().to_string(),
mnemonic: value["mnemonic"].as_str().unwrap().to_string(),
network: value["network"].as_str().unwrap().to_string(),
address: (
value["main-address"].as_str().unwrap().to_string(),
value["test-address"].as_str().unwrap().to_string(),
),
};

let account_conf = config::account();
let mut send_info = sendinfo::Info::default();
send_info.recipient_address = receive_address.to_string();
send_info.fee_rate = feerate.parse().unwrap();
send_info.max_fee_rate = account_conf.max_feerate as u64;
send_info.max_fee_amount = account_conf.max_fee_amount as u64;
let send_info = send_info
.amount_from_btc(
send_amount.as_str(),
&format!("{}", account_conf.max_send_amount),
)
.unwrap();

match tx::build(&password, address_info, send_info).await {
Err(e) => async_message_warn(
ui.clone(),
format!("{}. {}: {e:?}", tr("生成交易失败"), tr("原因")),
),
Ok(tx_detail) => {
log::debug!("{tx_detail:?}");
// TODO
}
}
}
},
Err(e) => async_message_warn(
ui.clone(),
format!("{}. {}: {e:?}", tr("生成交易失败"), tr("原因")),
),
}
});
},
);
}
3 changes: 2 additions & 1 deletion bitbox/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod util;
mod version;
mod wallet;

use logic::{about, address_book, btcinfo, clipboard, message, ok_cancel_dialog, password_dialog, account, activity, setting, window};
use logic::{about, address_book, btcinfo, clipboard, message, ok_cancel_dialog, password_dialog, send_tx, account, activity, setting, window};

use anyhow::Result;
use chrono::Local;
Expand Down Expand Up @@ -46,6 +46,7 @@ async fn main() -> Result<()> {
password_dialog::init(&ui);

account::init(&ui);
send_tx::init(&ui);
activity::init(&ui);
address_book::init(&ui);
btcinfo::init(&ui);
Expand Down
2 changes: 2 additions & 0 deletions bitbox/src/util/translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub fn tr(text: &str) -> String {
items.insert("组记词错误", "Mnemonic is wrong");
items.insert("恢复账户失败", "Recover account failed");
items.insert("切换网络成功", "Switch network success");
items.insert("非法输入", "Invalid input");
items.insert("生成交易失败", "Generate translation failed");
items.insert("刷新...", "Flush...");
items.insert("在线", "Online");
items.insert("正忙", "Busy");
Expand Down
1 change: 0 additions & 1 deletion bitbox/src/wallet/account/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ pub const ACCOUNT_DERIVATION_PATH: &str = "m/0'/0'";
pub struct Info {
pub uuid: String,
pub name: String,
pub balance: u64, // satoshi
pub mnemonic: String,
pub network: String,
pub address: (String, String),
Expand Down
Loading

0 comments on commit 61b89dc

Please sign in to comment.