Skip to content

Commit bfd7b2f

Browse files
committed
Allow creating transactions with dust outputs
Add TxBuilder::allow_dust() that skips checking the dust limit
1 parent 061f15a commit bfd7b2f

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
- Add capacity to create FeeRate from sats/kvbytes and sats/kwu.
99
- Rename `as_sat_vb` to `as_sat_per_vb`. Move all `FeeRate` test to `types.rs`.
1010
- Add custom Harware Wallet Signer `HwiSigner` in `src/wallet/harwaresigner/` module.
11+
- Add `allow_dust` method on `TxBuilder`.
1112

1213
## [v0.21.0] - [v0.20.0]
1314

@@ -22,14 +23,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2223
- New `RpcBlockchain` implementation with various fixes.
2324
- Return balance in separate categories, namely `confirmed`, `trusted_pending`, `untrusted_pending` & `immature`.
2425

25-
2626
## [v0.20.0] - [v0.19.0]
2727

2828
- New MSRV set to `1.56.1`
2929
- 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)
3030
- Fix hang when `ElectrumBlockchainConfig::stop_gap` is zero.
3131
- Set coin type in BIP44, BIP49, and BIP84 templates
32-
- 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.
32+
- 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.
3333
- Add `remove_partial_sigs` and `try_finalize` to `SignOptions`
3434
- Deprecate `AddressValidator`
3535
- 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
4141
- Unpinned tokio to `1`
4242
- Add traits to reuse `Blockchain`s across multiple wallets (`BlockchainFactory` and `StatelessBlockchain`).
4343
- Upgrade to rust-bitcoin `0.28`
44-
- If using the `sqlite-db` feature all cached wallet data is deleted due to a possible UTXO inconsistency, a wallet.sync will recreate it
44+
- If using the `sqlite-db` feature all cached wallet data is deleted due to a possible UTXO inconsistency, a wallet.sync will recreate it
4545
- Update `PkOrF` in the policy module to become an enum
4646
- Add experimental support for Taproot, including:
4747
- 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
5858
- Add `keychain: KeychainKind` to `wallet::AddressInfo`.
5959
- Improve key generation traits
6060
- Rename `WalletExport` to `FullyNodedExport`, deprecate the former.
61-
- Bump `miniscript` dependency version to `^6.1`.
61+
- Bump `miniscript` dependency version to `^6.1`.
6262

6363
## [v0.17.0] - [v0.16.1]
6464

src/wallet/mod.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,10 @@ where
790790
let recipients = params.recipients.iter().map(|(r, v)| (r, *v));
791791

792792
for (index, (script_pubkey, value)) in recipients.enumerate() {
793-
if value.is_dust(script_pubkey) && !script_pubkey.is_provably_unspendable() {
793+
if !params.allow_dust
794+
&& value.is_dust(script_pubkey)
795+
&& !script_pubkey.is_provably_unspendable()
796+
{
794797
return Err(Error::OutputBelowDustLimit(index));
795798
}
796799

@@ -5408,6 +5411,30 @@ pub(crate) mod test {
54085411
builder.finish().unwrap();
54095412
}
54105413

5414+
#[test]
5415+
fn test_allow_dust_limit() {
5416+
let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv());
5417+
5418+
let addr = wallet.get_address(New).unwrap();
5419+
5420+
let mut builder = wallet.build_tx();
5421+
5422+
builder.add_recipient(addr.script_pubkey(), 0);
5423+
5424+
assert!(matches!(
5425+
builder.finish().unwrap_err(),
5426+
Error::OutputBelowDustLimit(0)
5427+
));
5428+
5429+
let mut builder = wallet.build_tx();
5430+
5431+
builder
5432+
.allow_dust(true)
5433+
.add_recipient(addr.script_pubkey(), 0);
5434+
5435+
assert!(builder.finish().is_ok());
5436+
}
5437+
54115438
#[test]
54125439
fn test_fee_rate_sign_no_grinding_high_r() {
54135440
// Our goal is to obtain a transaction with a signature with high-R (71 bytes

src/wallet/tx_builder.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ pub(crate) struct TxParams {
148148
pub(crate) include_output_redeem_witness_script: bool,
149149
pub(crate) bumping_fee: Option<PreviousFee>,
150150
pub(crate) current_height: Option<u32>,
151+
pub(crate) allow_dust: bool,
151152
}
152153

153154
#[derive(Clone, Copy, Debug)]
@@ -560,6 +561,14 @@ impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext>
560561
self.params.current_height = Some(height);
561562
self
562563
}
564+
565+
/// Set whether or not the dust limit is checked.
566+
///
567+
/// **Note**: by avoiding a dust limit check you may end up with a transaction that is non-standard.
568+
pub fn allow_dust(&mut self, allow_dust: bool) -> &mut Self {
569+
self.params.allow_dust = allow_dust;
570+
self
571+
}
563572
}
564573

565574
impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>> TxBuilder<'a, D, Cs, CreateTx> {

0 commit comments

Comments
 (0)