1
0
forked from GRIN/grim

Review page: show live network fee for the amount (priced like GRIM's send modal)

This commit is contained in:
2ro
2026-06-15 21:18:34 -04:00
parent b7c3b95f51
commit 6a0c2565b5
2 changed files with 35 additions and 5 deletions
+22 -5
View File
@@ -138,6 +138,9 @@ pub struct SendFlow {
/// Set when the success screen's "Receipt" button is tapped: the host view
/// opens the receipt for the latest tx with this npub after the flow closes.
pub receipt_npub: Option<String>,
/// Atomic amount (nanogrin) we last asked the wallet to price, so the review
/// page dispatches one `CalculateFee` per amount instead of every frame.
fee_requested_for: Option<u64>,
}
impl Default for SendFlow {
@@ -162,6 +165,7 @@ impl Default for SendFlow {
scan_open: false,
request: false,
receipt_npub: None,
fee_requested_for: None,
}
}
}
@@ -1115,11 +1119,24 @@ impl SendFlow {
&t!("goblin.send.row_delivery_val"),
);
} else {
w::info_row(
ui,
&t!("goblin.send.row_network_fee"),
&t!("goblin.send.row_network_fee_val"),
);
// Live network fee for this exact amount, priced by the wallet (one
// async CalculateFee per amount, like GRIM's send modal). Until the
// first result lands we show an ellipsis rather than a wrong number.
let amount_nano = amount_from_hr_string(&amount).unwrap_or(0);
if amount_nano > 0 && self.fee_requested_for != Some(amount_nano) {
self.fee_requested_for = Some(amount_nano);
wallet.task(WalletTask::CalculateFee(amount_nano, 0));
}
let fee_val = match wallet.calculated_fee(amount_nano) {
Some(fee) => format!("{} {}", w::amount_str(fee), w::TSU),
None => {
// Result lands on a worker thread; poll until it does.
ui.ctx()
.request_repaint_after(std::time::Duration::from_millis(120));
"".to_string()
}
};
w::info_row(ui, &t!("goblin.send.row_network_fee"), &fee_val);
w::info_row(
ui,
&t!("goblin.send.row_privacy"),
+13
View File
@@ -126,6 +126,9 @@ pub struct Wallet {
/// Amount requests to calculate fee.
fee_calculating: Arc<AtomicU8>,
/// Last calculated network fee as `(amount, fee)` so a screen can read the
/// fee for the amount it is showing without owning the task-result slot.
last_fee: Arc<RwLock<Option<(u64, u64)>>>,
/// Flag to check if sending request is creating.
send_creating: Arc<AtomicBool>,
@@ -176,6 +179,7 @@ impl Wallet {
message_opening: Arc::new(AtomicBool::from(false)),
send_creating: Arc::new(AtomicBool::new(false)),
fee_calculating: Arc::new(AtomicU8::new(0)),
last_fee: Arc::new(RwLock::new(None)),
invoice_creating: Arc::new(AtomicBool::new(false)),
proof_verifying: Arc::new(AtomicBool::new(false)),
tasks_sender: Arc::new(RwLock::new(None)),
@@ -1389,6 +1393,14 @@ impl Wallet {
self.fee_calculating.load(Ordering::Relaxed) > 0
}
/// Last calculated network fee for `amount`, if one is cached. Returns
/// `None` until a `CalculateFee` task for that exact amount has completed.
pub fn calculated_fee(&self, amount: u64) -> Option<u64> {
self.last_fee
.read()
.and_then(|(a, f)| if a == amount { Some(f) } else { None })
}
/// Initialize a transaction to send amount.
fn send(&self, a: u64, dest: Option<SlatepackAddress>) -> Result<Slate, Error> {
let config = self.get_config();
@@ -2154,6 +2166,7 @@ async fn handle_task(w: &Wallet, t: WalletTask) {
}
// Calculate fee for provided amount.
if let Ok(fee) = w.calculate_fee(*a) {
*w.last_fee.write() = Some((*a, fee));
w.on_task_result(None, &WalletTask::CalculateFee(*a, fee))
}
let calculating = w.fee_calculating.load(Ordering::Relaxed);