Skip to content

Commit

Permalink
Allow using custom fee rate (ordinals#1150)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphjaph authored Jan 12, 2023
1 parent 735b125 commit 6659850
Show file tree
Hide file tree
Showing 11 changed files with 324 additions and 50 deletions.
66 changes: 66 additions & 0 deletions src/fee_rate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use super::*;

#[derive(Debug, PartialEq, Clone, Copy)]
pub(crate) struct FeeRate(f64);

impl FromStr for FeeRate {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(f64::from_str(s)?)
}
}

impl TryFrom<f64> for FeeRate {
type Error = Error;

fn try_from(rate: f64) -> Result<Self, Self::Error> {
if rate.is_sign_negative() | rate.is_nan() | rate.is_infinite() {
bail!("invalid fee rate: {rate}")
}
Ok(Self(rate))
}
}

impl FeeRate {
pub(crate) fn fee(&self, vsize: usize) -> Amount {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
Amount::from_sat((self.0 * vsize as f64).round() as u64)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn parse() {
assert_eq!("1.1".parse::<FeeRate>().unwrap().0, 1.1);
assert_eq!("11.19".parse::<FeeRate>().unwrap().0, 11.19);
assert_eq!("11.1111".parse::<FeeRate>().unwrap().0, 11.1111);
assert!("-4.2".parse::<FeeRate>().is_err());
assert!(FeeRate::try_from(f64::INFINITY).is_err());
assert!(FeeRate::try_from(f64::NAN).is_err());
}

#[test]
fn fee() {
assert_eq!(
"2.5".parse::<FeeRate>().unwrap().fee(100),
Amount::from_sat(250)
);
assert_eq!(
"2.0".parse::<FeeRate>().unwrap().fee(1024),
Amount::from_sat(2048)
);
assert_eq!(
"1.1".parse::<FeeRate>().unwrap().fee(100),
Amount::from_sat(110)
);
assert_eq!(
"1.0".parse::<FeeRate>().unwrap().fee(123456789),
Amount::from_sat(123456789)
);
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ mod content;
mod decimal;
mod degree;
mod epoch;
mod fee_rate;
mod height;
mod index;
mod inscription;
Expand Down
3 changes: 2 additions & 1 deletion src/subcommand/preview.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::*;
use {super::*, fee_rate::FeeRate};

#[derive(Debug, Parser)]
pub(crate) struct Preview {
Expand Down Expand Up @@ -77,6 +77,7 @@ impl Preview {
options: options.clone(),
subcommand: Subcommand::Wallet(super::wallet::Wallet::Inscribe(
super::wallet::inscribe::Inscribe {
fee_rate: FeeRate::try_from(1.0).unwrap(),
file,
no_backup: true,
satpoint: None,
Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use {super::*, transaction_builder::TransactionBuilder};
use {super::*, fee_rate::FeeRate, transaction_builder::TransactionBuilder};

mod balance;
pub(crate) mod create;
Expand Down
67 changes: 64 additions & 3 deletions src/subcommand/wallet/inscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ use {
pub(crate) struct Inscribe {
#[clap(long, help = "Inscribe <SATPOINT>")]
pub(crate) satpoint: Option<SatPoint>,
#[clap(
long,
default_value = "1.0",
help = "Use fee rate of <FEE_RATE> sats/vB"
)]
pub(crate) fee_rate: FeeRate,
#[clap(help = "Inscribe sat with contents of <FILE>")]
pub(crate) file: PathBuf,
#[clap(long, help = "Do not back up recovery key.")]
Expand Down Expand Up @@ -52,6 +58,7 @@ impl Inscribe {
utxos,
commit_tx_change,
reveal_tx_destination,
self.fee_rate,
)?;

if !self.no_backup {
Expand Down Expand Up @@ -83,6 +90,7 @@ impl Inscribe {
utxos: BTreeMap<OutPoint, Amount>,
change: Vec<Address>,
destination: Address,
fee_rate: FeeRate,
) -> Result<(Transaction, Transaction, TweakedKeyPair)> {
let satpoint = if let Some(satpoint) = satpoint {
satpoint
Expand Down Expand Up @@ -143,6 +151,7 @@ impl Inscribe {
utxos,
commit_tx_address.clone(),
change,
fee_rate,
)?;

let (vout, output) = unsigned_commit_tx
Expand Down Expand Up @@ -181,7 +190,7 @@ impl Inscribe {
reveal_tx.input[0].witness.push(&reveal_script);
reveal_tx.input[0].witness.push(&control_block.serialize());

TransactionBuilder::TARGET_FEE_RATE * reveal_tx.vsize().try_into().unwrap()
fee_rate.fee(reveal_tx.vsize())
};

reveal_tx.output[0].value = reveal_tx.output[0]
Expand Down Expand Up @@ -279,10 +288,13 @@ mod tests {
utxos.into_iter().collect(),
vec![commit_address, change(1)],
reveal_address,
FeeRate::try_from(1.0).unwrap(),
)
.unwrap();

let fee = TransactionBuilder::TARGET_FEE_RATE * reveal_tx.vsize().try_into().unwrap();
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
let fee = Amount::from_sat((1.0 * (reveal_tx.vsize() as f64)).ceil() as u64);

assert_eq!(
reveal_tx.output[0].value,
Expand All @@ -306,6 +318,7 @@ mod tests {
utxos.into_iter().collect(),
vec![commit_address, change(1)],
reveal_address,
FeeRate::try_from(1.0).unwrap(),
)
.unwrap_err()
.to_string()
Expand All @@ -314,7 +327,7 @@ mod tests {

#[test]
fn reveal_transaction_would_create_dust() {
let utxos = vec![(outpoint(1), Amount::from_sat(600))];
let utxos = vec![(outpoint(1), Amount::from_sat(500))];
let inscription = inscription("text/plain", "ord");
let satpoint = Some(satpoint(1, 0));
let commit_address = change(0);
Expand All @@ -328,6 +341,7 @@ mod tests {
utxos.into_iter().collect(),
vec![commit_address, change(1)],
reveal_address,
FeeRate::try_from(1.0).unwrap(),
)
.unwrap_err()
.to_string();
Expand All @@ -354,6 +368,7 @@ mod tests {
utxos.into_iter().collect(),
vec![commit_address, change(1)],
reveal_address,
FeeRate::try_from(1.0).unwrap(),
)
.unwrap();

Expand Down Expand Up @@ -386,6 +401,7 @@ mod tests {
utxos.into_iter().collect(),
vec![commit_address, change(1)],
reveal_address,
FeeRate::try_from(1.0).unwrap(),
)
.unwrap_err()
.to_string();
Expand Down Expand Up @@ -425,7 +441,52 @@ mod tests {
utxos.into_iter().collect(),
vec![commit_address, change(1)],
reveal_address,
FeeRate::try_from(1.0).unwrap(),
)
.is_ok())
}

#[test]
fn inscribe_with_custom_fee_rate() {
let utxos = vec![
(outpoint(1), Amount::from_sat(10_000)),
(outpoint(2), Amount::from_sat(10_000)),
];
let mut inscriptions = BTreeMap::new();
inscriptions.insert(
SatPoint {
outpoint: outpoint(1),
offset: 0,
},
Txid::from_str("06413a3ef4232f0485df2bc7c912c13c05c69f967c19639344753e05edb64bd5").unwrap(),
);

let inscription = inscription("text/plain", "ord");
let satpoint = None;
let commit_address = change(0);
let reveal_address = recipient();
let fee_rate = 3.3;

let (commit_tx, reveal_tx, _private_key) = Inscribe::create_inscription_transactions(
satpoint,
inscription,
inscriptions,
bitcoin::Network::Signet,
utxos.into_iter().collect(),
vec![commit_address, change(1)],
reveal_address,
FeeRate::try_from(fee_rate).unwrap(),
)
.unwrap();

let fee = FeeRate::try_from(fee_rate)
.unwrap()
.fee(reveal_tx.vsize())
.to_sat();

assert_eq!(
reveal_tx.output[0].value,
10_000 - fee - (10_000 - commit_tx.output[0].value),
);
}
}
7 changes: 7 additions & 0 deletions src/subcommand/wallet/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ use super::*;
pub(crate) struct Send {
address: Address,
outgoing: Outgoing,
#[clap(
long,
default_value = "1.0",
help = "Use fee rate of <FEE_RATE> sats/vB"
)]
fee_rate: FeeRate,
}

impl Send {
Expand Down Expand Up @@ -70,6 +76,7 @@ impl Send {
unspent_outputs,
self.address,
change,
self.fee_rate,
)?;

let signed_tx = client
Expand Down
Loading

0 comments on commit 6659850

Please sign in to comment.