From 53d77990d3698665a1f92d4fce57968c025feba6 Mon Sep 17 00:00:00 2001 From: Greg Martin Date: Fri, 31 Mar 2023 17:54:40 +0000 Subject: [PATCH] Add flags to `wallet inscribe` and `wallet send` to allow setting the postage sizes. --- src/subcommand/preview.rs | 1 + src/subcommand/wallet/inscribe.rs | 17 +++- src/subcommand/wallet/send.rs | 12 +++ src/subcommand/wallet/transaction_builder.rs | 82 ++++++++++++++++++-- 4 files changed, 105 insertions(+), 7 deletions(-) diff --git a/src/subcommand/preview.rs b/src/subcommand/preview.rs index d9f402e47e..5ab7173bc5 100644 --- a/src/subcommand/preview.rs +++ b/src/subcommand/preview.rs @@ -86,6 +86,7 @@ impl Preview { dry_run: false, no_limit: false, destination: None, + postage: Some(TransactionBuilder::DEFAULT_TARGET_POSTAGE), }, )), } diff --git a/src/subcommand/wallet/inscribe.rs b/src/subcommand/wallet/inscribe.rs index 1df5c15061..f8e53a9677 100644 --- a/src/subcommand/wallet/inscribe.rs +++ b/src/subcommand/wallet/inscribe.rs @@ -50,6 +50,8 @@ pub(crate) struct Inscribe { pub(crate) dry_run: bool, #[clap(long, help = "Send inscription to .")] pub(crate) destination: Option
, + #[clap(long, help = "Amount of postage to include in the inscription. Default `10000 sats`")] + pub(crate) postage: Option, } impl Inscribe { @@ -84,6 +86,10 @@ impl Inscribe { self.commit_fee_rate.unwrap_or(self.fee_rate), self.fee_rate, self.no_limit, + match self.postage { + Some(postage) => postage, + _ => TransactionBuilder::DEFAULT_TARGET_POSTAGE, + }, )?; utxos.insert( @@ -151,6 +157,7 @@ impl Inscribe { commit_fee_rate: FeeRate, reveal_fee_rate: FeeRate, no_limit: bool, + postage: Amount, ) -> Result<(Transaction, Transaction, TweakedKeyPair)> { let satpoint = if let Some(satpoint) = satpoint { satpoint @@ -223,7 +230,7 @@ impl Inscribe { commit_tx_address.clone(), change, commit_fee_rate, - reveal_fee + TransactionBuilder::TARGET_POSTAGE, + reveal_fee + postage, )?; let (vout, output) = unsigned_commit_tx @@ -389,6 +396,7 @@ mod tests { FeeRate::try_from(1.0).unwrap(), FeeRate::try_from(1.0).unwrap(), false, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .unwrap(); @@ -420,6 +428,7 @@ mod tests { FeeRate::try_from(1.0).unwrap(), FeeRate::try_from(1.0).unwrap(), false, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .unwrap(); @@ -455,6 +464,7 @@ mod tests { FeeRate::try_from(1.0).unwrap(), FeeRate::try_from(1.0).unwrap(), false, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .unwrap_err() .to_string(); @@ -497,6 +507,7 @@ mod tests { FeeRate::try_from(1.0).unwrap(), FeeRate::try_from(1.0).unwrap(), false, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .is_ok()) } @@ -533,6 +544,7 @@ mod tests { FeeRate::try_from(fee_rate).unwrap(), FeeRate::try_from(fee_rate).unwrap(), false, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .unwrap(); @@ -595,6 +607,7 @@ mod tests { FeeRate::try_from(commit_fee_rate).unwrap(), FeeRate::try_from(fee_rate).unwrap(), false, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .unwrap(); @@ -644,6 +657,7 @@ mod tests { FeeRate::try_from(1.0).unwrap(), FeeRate::try_from(1.0).unwrap(), false, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .unwrap_err() .to_string(); @@ -675,6 +689,7 @@ mod tests { FeeRate::try_from(1.0).unwrap(), FeeRate::try_from(1.0).unwrap(), true, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, ) .unwrap(); diff --git a/src/subcommand/wallet/send.rs b/src/subcommand/wallet/send.rs index 85a22f3c09..34e2209e37 100644 --- a/src/subcommand/wallet/send.rs +++ b/src/subcommand/wallet/send.rs @@ -6,6 +6,10 @@ pub(crate) struct Send { outgoing: Outgoing, #[clap(long, help = "Use fee rate of sats/vB")] fee_rate: FeeRate, + #[clap(long, help = "Target amount of postage to include in the sent output. Default `10000 sats`")] + pub(crate) target_postage: Option, + #[clap(long, help = "Maximum amount of postage to include in the sent output. Default `20000 sats`")] + pub(crate) max_postage: Option, } #[derive(Serialize, Deserialize)] @@ -78,6 +82,14 @@ impl Send { self.address, change, self.fee_rate, + match self.target_postage { + Some(target_postage) => target_postage, + _ => TransactionBuilder::DEFAULT_TARGET_POSTAGE, + }, + match self.max_postage { + Some(max_postage) => max_postage, + _ => TransactionBuilder::DEFAULT_MAX_POSTAGE, + }, )?; let signed_tx = client diff --git a/src/subcommand/wallet/transaction_builder.rs b/src/subcommand/wallet/transaction_builder.rs index 11f73d4f65..c2fac0a33b 100644 --- a/src/subcommand/wallet/transaction_builder.rs +++ b/src/subcommand/wallet/transaction_builder.rs @@ -107,6 +107,8 @@ pub struct TransactionBuilder { unused_change_addresses: Vec
, utxos: BTreeSet, target: Target, + target_postage: Amount, + max_postage: Amount, } type Result = std::result::Result; @@ -114,9 +116,9 @@ type Result = std::result::Result; impl TransactionBuilder { const ADDITIONAL_INPUT_VBYTES: usize = 58; const ADDITIONAL_OUTPUT_VBYTES: usize = 43; - const MAX_POSTAGE: Amount = Amount::from_sat(2 * 10_000); const SCHNORR_SIGNATURE_SIZE: usize = 64; - pub(crate) const TARGET_POSTAGE: Amount = Amount::from_sat(10_000); + pub(crate) const DEFAULT_MAX_POSTAGE: Amount = Amount::from_sat(2 * 10_000); + pub(crate) const DEFAULT_TARGET_POSTAGE: Amount = Amount::from_sat(10_000); pub fn build_transaction_with_postage( outgoing: SatPoint, @@ -125,6 +127,8 @@ impl TransactionBuilder { recipient: Address, change: [Address; 2], fee_rate: FeeRate, + target_postage: Amount, + max_postage: Amount, ) -> Result { Self::new( outgoing, @@ -134,6 +138,8 @@ impl TransactionBuilder { change, fee_rate, Target::Postage, + target_postage, + max_postage, )? .build_transaction() } @@ -164,6 +170,8 @@ impl TransactionBuilder { change, fee_rate, Target::Value(output_value), + Amount::from_sat(0), + Amount::from_sat(0), )? .build_transaction() } @@ -187,6 +195,8 @@ impl TransactionBuilder { change: [Address; 2], fee_rate: FeeRate, target: Target, + target_postage: Amount, + max_postage: Amount, ) -> Result { if change.contains(&recipient) { return Err(Error::DuplicateAddress(recipient)); @@ -208,6 +218,8 @@ impl TransactionBuilder { recipient, unused_change_addresses: change.to_vec(), target, + target_postage, + max_postage, }) } @@ -342,7 +354,7 @@ impl TransactionBuilder { if let Some(excess) = value.checked_sub(self.fee_rate.fee(self.estimate_vbytes())) { let (max, target) = match self.target { - Target::Postage => (Self::MAX_POSTAGE, Self::TARGET_POSTAGE), + Target::Postage => (self.max_postage, self.target_postage), Target::Value(value) => (value, value), }; @@ -554,7 +566,7 @@ impl TransactionBuilder { match self.target { Target::Postage => { assert!( - Amount::from_sat(output.value) <= Self::MAX_POSTAGE + slop, + Amount::from_sat(output.value) <= self.max_postage + slop, "invariant: excess postage is stripped" ); } @@ -681,6 +693,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -724,6 +738,8 @@ mod tests { (change(1), Amount::from_sat(1_724)), ], target: Target::Postage, + target_postage: TransactionBuilder::DEFAULT_TARGET_POSTAGE, + max_postage: TransactionBuilder::DEFAULT_MAX_POSTAGE, }; pretty_assert_eq!( @@ -752,6 +768,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .is_explicitly_rbf()) @@ -769,6 +787,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1, @@ -792,6 +812,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -816,6 +838,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1, @@ -838,6 +862,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Err(Error::NotEnoughCardinalUtxos), ) @@ -858,6 +884,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Err(Error::NotEnoughCardinalUtxos), ) @@ -878,6 +906,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1, @@ -885,7 +915,7 @@ mod tests { input: vec![tx_in(outpoint(1)), tx_in(outpoint(2))], output: vec![ tx_out(4_950, change(1)), - tx_out(TransactionBuilder::TARGET_POSTAGE.to_sat(), recipient()), + tx_out(TransactionBuilder::DEFAULT_TARGET_POSTAGE.to_sat(), recipient()), tx_out(14_831, change(0)), ], }) @@ -905,6 +935,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .build() @@ -924,6 +956,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .build() @@ -943,6 +977,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .build() @@ -962,6 +998,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -987,6 +1025,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -1009,13 +1049,15 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1, lock_time: PackedLockTime::ZERO, input: vec![tx_in(outpoint(1))], output: vec![ - tx_out(TransactionBuilder::TARGET_POSTAGE.to_sat(), recipient()), + tx_out(TransactionBuilder::DEFAULT_TARGET_POSTAGE.to_sat(), recipient()), tx_out(989_870, change(1)) ], }) @@ -1035,6 +1077,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -1055,6 +1099,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1, @@ -1080,6 +1126,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1, @@ -1103,6 +1151,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -1131,6 +1181,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -1157,6 +1209,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -1180,6 +1234,8 @@ mod tests { [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), Target::Postage, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap() .select_outgoing() @@ -1213,6 +1269,8 @@ mod tests { (change(1), Amount::from_sat(1_774)), ], target: Target::Postage, + target_postage: TransactionBuilder::DEFAULT_TARGET_POSTAGE, + max_postage: TransactionBuilder::DEFAULT_MAX_POSTAGE, } .build() .unwrap(); @@ -1242,6 +1300,8 @@ mod tests { (change(0), Amount::from_sat(1_774)), ], target: Target::Postage, + target_postage: TransactionBuilder::DEFAULT_TARGET_POSTAGE, + max_postage: TransactionBuilder::DEFAULT_MAX_POSTAGE, } .build() .unwrap(); @@ -1262,6 +1322,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Err(Error::NotEnoughCardinalUtxos) ) @@ -1279,6 +1341,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Err(Error::UtxoContainsAdditionalInscription { outgoing_satpoint: satpoint(1, 0), @@ -1301,6 +1365,8 @@ mod tests { recipient(), [change(0), change(1)], fee_rate, + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ) .unwrap(); @@ -1486,6 +1552,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(1.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1, @@ -1608,6 +1676,8 @@ mod tests { recipient(), [change(0), change(1)], FeeRate::try_from(250.0).unwrap(), + TransactionBuilder::DEFAULT_TARGET_POSTAGE, + TransactionBuilder::DEFAULT_MAX_POSTAGE, ), Ok(Transaction { version: 1,