diff --git a/CHANGELOG.md b/CHANGELOG.md index 2859b7ee..98cbd0da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add capacity to create FeeRate from sats/kvbytes and sats/kwu. - Rename `as_sat_vb` to `as_sat_per_vb`. Move all `FeeRate` test to `types.rs`. - Add custom Harware Wallet Signer `HwiSigner` in `src/wallet/harwaresigner/` module. +- Add `allow_dust` method on `TxBuilder`. ## [v0.21.0] - [v0.20.0] @@ -22,14 +23,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New `RpcBlockchain` implementation with various fixes. - Return balance in separate categories, namely `confirmed`, `trusted_pending`, `untrusted_pending` & `immature`. - ## [v0.20.0] - [v0.19.0] - New MSRV set to `1.56.1` - Fee sniping discouraging through nLockTime - if the user specifies a `current_height`, we use that as a nlocktime, otherwise we use the last sync height (or 0 if we never synced) - Fix hang when `ElectrumBlockchainConfig::stop_gap` is zero. - Set coin type in BIP44, BIP49, and BIP84 templates -- Get block hash given a block height - A `get_block_hash` method is now defined on the `GetBlockHash` trait and implemented on every blockchain backend. This method expects a block height and returns the corresponding block hash. +- Get block hash given a block height - A `get_block_hash` method is now defined on the `GetBlockHash` trait and implemented on every blockchain backend. This method expects a block height and returns the corresponding block hash. - Add `remove_partial_sigs` and `try_finalize` to `SignOptions` - Deprecate `AddressValidator` - Fix Electrum wallet sync potentially causing address index decrement - compare proposed index and current index before applying batch operations during sync. @@ -41,7 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Unpinned tokio to `1` - Add traits to reuse `Blockchain`s across multiple wallets (`BlockchainFactory` and `StatelessBlockchain`). - Upgrade to rust-bitcoin `0.28` -- If using the `sqlite-db` feature all cached wallet data is deleted due to a possible UTXO inconsistency, a wallet.sync will recreate it +- If using the `sqlite-db` feature all cached wallet data is deleted due to a possible UTXO inconsistency, a wallet.sync will recreate it - Update `PkOrF` in the policy module to become an enum - Add experimental support for Taproot, including: - Support for `tr()` descriptors with complex tapscript trees @@ -58,7 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `keychain: KeychainKind` to `wallet::AddressInfo`. - Improve key generation traits - Rename `WalletExport` to `FullyNodedExport`, deprecate the former. -- Bump `miniscript` dependency version to `^6.1`. +- Bump `miniscript` dependency version to `^6.1`. ## [v0.17.0] - [v0.16.1] diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 5e413a63..c01b8b17 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -790,7 +790,10 @@ where let recipients = params.recipients.iter().map(|(r, v)| (r, *v)); for (index, (script_pubkey, value)) in recipients.enumerate() { - if value.is_dust(script_pubkey) && !script_pubkey.is_provably_unspendable() { + if !params.allow_dust + && value.is_dust(script_pubkey) + && !script_pubkey.is_provably_unspendable() + { return Err(Error::OutputBelowDustLimit(index)); } @@ -5408,6 +5411,30 @@ pub(crate) mod test { builder.finish().unwrap(); } + #[test] + fn test_allow_dust_limit() { + let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); + + let addr = wallet.get_address(New).unwrap(); + + let mut builder = wallet.build_tx(); + + builder.add_recipient(addr.script_pubkey(), 0); + + assert!(matches!( + builder.finish().unwrap_err(), + Error::OutputBelowDustLimit(0) + )); + + let mut builder = wallet.build_tx(); + + builder + .allow_dust(true) + .add_recipient(addr.script_pubkey(), 0); + + assert!(builder.finish().is_ok()); + } + #[test] fn test_fee_rate_sign_no_grinding_high_r() { // Our goal is to obtain a transaction with a signature with high-R (71 bytes diff --git a/src/wallet/tx_builder.rs b/src/wallet/tx_builder.rs index 9e93e551..c02ff3a2 100644 --- a/src/wallet/tx_builder.rs +++ b/src/wallet/tx_builder.rs @@ -148,6 +148,7 @@ pub(crate) struct TxParams { pub(crate) include_output_redeem_witness_script: bool, pub(crate) bumping_fee: Option, pub(crate) current_height: Option, + pub(crate) allow_dust: bool, } #[derive(Clone, Copy, Debug)] @@ -560,6 +561,14 @@ impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderContext> self.params.current_height = Some(height); self } + + /// Set whether or not the dust limit is checked. + /// + /// **Note**: by avoiding a dust limit check you may end up with a transaction that is non-standard. + pub fn allow_dust(&mut self, allow_dust: bool) -> &mut Self { + self.params.allow_dust = allow_dust; + self + } } impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm> TxBuilder<'a, D, Cs, CreateTx> {