Skip to content

Commit

Permalink
Merge pull request #2194 from get10101/fix/estimate-fee-error
Browse files Browse the repository at this point in the history
Do not error when user is typing send amount
  • Loading branch information
luckysori committed Mar 8, 2024
2 parents 669cdda + 46fea4d commit 517feda
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 24 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/ln-dlc-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ secp256k1-zkp = { version = "0.7.0", features = ["global-context"] }
serde = "1.0.147"
serde_with = "3.1.0"
sha2 = "0.10"
thiserror = "1"
time = "0.3"
tokio = { version = "1", default-features = false, features = ["io-util", "macros", "rt", "rt-multi-thread", "sync", "time", "tracing"] }
tracing = "0.1.37"
Expand Down
1 change: 1 addition & 0 deletions crates/ln-dlc-node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub use ln::DlcChannelDetails;
pub use ln::EventHandlerTrait;
pub use ln::EventSender;
pub use on_chain_wallet::ConfirmationStatus;
pub use on_chain_wallet::EstimateFeeError;
pub use on_chain_wallet::TransactionDetails;

#[cfg(test)]
Expand Down
14 changes: 0 additions & 14 deletions crates/ln-dlc-node/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use bitcoin::address::NetworkUnchecked;
use bitcoin::secp256k1::PublicKey;
use bitcoin::secp256k1::XOnlyPublicKey;
use bitcoin::Address;
use bitcoin::Amount;
use bitcoin::Network;
use bitcoin::Txid;
use dlc_messages::message_handler::MessageHandler as DlcMessageHandler;
Expand Down Expand Up @@ -538,19 +537,6 @@ impl<D: BdkStorage, S: TenTenOneStorage + 'static, N: Storage + Sync + Send + 's
)
}

/// Estimate the fee for sending the given `amount_sats` to the given `address` on-chain with
/// the given `fee`.
pub fn estimate_fee(
&self,
address: Address<NetworkUnchecked>,
amount_sats: u64,
fee: ConfirmationTarget,
) -> Result<Amount> {
let address = address.require_network(self.network)?;

self.wallet.estimate_fee(&address, amount_sats, fee)
}

/// Send the given `amount_sats` sats to the given unchecked, on-chain `address`.
pub async fn send_to_address(
&self,
Expand Down
14 changes: 14 additions & 0 deletions crates/ln-dlc-node/src/node/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::bitcoin_conversion::to_secp_sk_30;
use crate::node::Node;
use crate::node::Storage;
use crate::on_chain_wallet;
use crate::on_chain_wallet::BdkStorage;
use crate::on_chain_wallet::OnChainWallet;
use crate::on_chain_wallet::TransactionDetails;
Expand All @@ -10,9 +11,11 @@ use anyhow::Result;
use bdk_esplora::EsploraAsyncExt;
use bitcoin::secp256k1::SecretKey;
use bitcoin::Address;
use bitcoin::Amount;
use bitcoin::OutPoint;
use bitcoin::ScriptBuf;
use bitcoin::TxOut;
use lightning::chain::chaininterface::ConfirmationTarget;
use std::sync::Arc;
use tokio::task::spawn_blocking;

Expand Down Expand Up @@ -60,6 +63,17 @@ impl<D: BdkStorage, S: TenTenOneStorage, N: Storage + Send + Sync + 'static> Nod
self.wallet.is_mine(script_pubkey)
}

/// Estimate the fee for sending the given `amount_sats` to the given `address` on-chain with
/// the given `fee`.
pub fn estimate_fee(
&self,
address: Address,
amount_sats: u64,
fee: ConfirmationTarget,
) -> Result<Amount, on_chain_wallet::EstimateFeeError> {
self.wallet.estimate_fee(&address, amount_sats, fee)
}

/// Sync the state of the on-chain wallet against the blockchain.
pub async fn sync_on_chain_wallet(&self) -> Result<()> {
let client = &self.blockchain.esplora_client_async;
Expand Down
15 changes: 14 additions & 1 deletion crates/ln-dlc-node/src/on_chain_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use bdk::chain::Append;
use bdk::chain::ChainPosition;
use bdk::chain::PersistBackend;
use bdk::psbt::PsbtUtils;
use bdk::wallet::IsDust;
use bdk::KeychainKind;
use bdk::LocalOutput;
use bdk::SignOptions;
Expand Down Expand Up @@ -377,7 +378,11 @@ where
recipient: &Address,
amount_sat_or_drain: u64,
confirmation_target: ConfirmationTarget,
) -> Result<Amount> {
) -> Result<Amount, EstimateFeeError> {
if amount_sat_or_drain.is_dust(&recipient.script_pubkey()) {
return Err(EstimateFeeError::SendAmountBelowDust);
}

let psbt = self.build_psbt(
recipient,
amount_sat_or_drain,
Expand Down Expand Up @@ -449,6 +454,14 @@ impl ConfirmationStatus {
}
}

#[derive(thiserror::Error, Debug)]
pub enum EstimateFeeError {
#[error("Cannot estimate fee for output below dust")]
SendAmountBelowDust,
#[error(transparent)]
Other(#[from] anyhow::Error),
}

pub trait BdkStorage: PersistBackend<bdk::wallet::ChangeSet> + Send + Sync + 'static {}

#[derive(Default)]
Expand Down
6 changes: 5 additions & 1 deletion mobile/native/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,11 @@ pub fn calculate_all_fees_for_on_chain(address: String, amount: u64) -> Result<V
let fee_rate = fee_rate(confirmation_target);

let fee_config = Fee::Priority(confirmation_target);
let absolute_fee = ln_dlc::estimate_payment_fee(amount, &address, fee_config).await?;
let absolute_fee =
match ln_dlc::estimate_payment_fee(amount, &address, fee_config).await? {
Some(fee) => fee,
None => Amount::ZERO,
};

fees.push(FeeEstimation {
sats_per_vbyte: fee_rate.ceil() as u64,
Expand Down
27 changes: 19 additions & 8 deletions mobile/native/src/ln_dlc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,18 +979,29 @@ pub fn estimated_funding_tx_fee() -> Result<Amount> {
Ok(fee)
}

pub async fn estimate_payment_fee(amount: u64, address: &str, fee: Fee) -> Result<Amount> {
let address = address.parse()?;
pub async fn estimate_payment_fee(amount: u64, address: &str, fee: Fee) -> Result<Option<Amount>> {
let address: Address<NetworkUnchecked> = address.parse().context("Failed to parse address")?;
// This is safe to do because we are only using this address to estimate a fee.
let address = address.assume_checked();

let fee = match fee {
Fee::Priority(target) => state::get_node()
.inner
.estimate_fee(address, amount, target.into())?
.to_sat(),
Fee::FeeRate { sats } => sats,
Fee::Priority(target) => {
match state::get_node()
.inner
.estimate_fee(address, amount, target.into())
{
Ok(fee) => Some(fee),
// It's not sensible to calculate the fee for an amount below dust.
Err(ln_dlc_node::EstimateFeeError::SendAmountBelowDust) => None,
Err(e) => {
bail!("Failed to estimate payment fee: {e:#}")
}
}
}
Fee::FeeRate { sats } => Some(Amount::from_sat(sats)),
};

Ok(Amount::from_sat(fee))
Ok(fee)
}

pub async fn trade(
Expand Down

0 comments on commit 517feda

Please sign in to comment.