xmr-btc-swap/swap/src/bitcoin/punish.rs
Philipp Hoenisch 1012e39527
Dynamically chose fee for TxRefund and TxPunish.
Alice chooses the fee for TxPunish because she is the one that cares.
Bob chooses the fee for TxRefund because he is the one that cares.

Note must be taken here because if the fee is too low (e.g. < min tx fee) then she might not be able to publish TxRedeem at all.
2021-05-07 10:24:41 +10:00

90 lines
2.5 KiB
Rust

use crate::bitcoin::wallet::Watchable;
use crate::bitcoin::{self, Address, Amount, PunishTimelock, Transaction, TxCancel, Txid};
use ::bitcoin::util::bip143::SigHashCache;
use ::bitcoin::{SigHash, SigHashType};
use anyhow::{Context, Result};
use bdk::bitcoin::Script;
use miniscript::{Descriptor, DescriptorTrait};
use std::collections::HashMap;
// TODO take real tx weight from past transaction
pub const ESTIMATED_WEIGHT: usize = 10_000;
#[derive(Debug)]
pub struct TxPunish {
inner: Transaction,
digest: SigHash,
cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>,
watch_script: Script,
}
impl TxPunish {
pub fn new(
tx_cancel: &TxCancel,
punish_address: &Address,
punish_timelock: PunishTimelock,
spending_fee: Amount,
) -> Self {
let tx_punish =
tx_cancel.build_spend_transaction(punish_address, Some(punish_timelock), spending_fee);
let digest = SigHashCache::new(&tx_punish).signature_hash(
0, // Only one input: cancel transaction
&tx_cancel.output_descriptor.script_code(),
tx_cancel.amount().as_sat(),
SigHashType::All,
);
Self {
inner: tx_punish,
digest,
cancel_output_descriptor: tx_cancel.output_descriptor.clone(),
watch_script: punish_address.script_pubkey(),
}
}
pub fn digest(&self) -> SigHash {
self.digest
}
pub fn complete(
self,
tx_punish_sig_bob: bitcoin::Signature,
a: bitcoin::SecretKey,
B: bitcoin::PublicKey,
) -> Result<Transaction> {
let sig_a = a.sign(self.digest());
let sig_b = tx_punish_sig_bob;
let satisfier = {
let mut satisfier = HashMap::with_capacity(2);
let A = a.public().into();
let B = B.into();
// The order in which these are inserted doesn't matter
satisfier.insert(A, (sig_a.into(), ::bitcoin::SigHashType::All));
satisfier.insert(B, (sig_b.into(), ::bitcoin::SigHashType::All));
satisfier
};
let mut tx_punish = self.inner;
self.cancel_output_descriptor
.satisfy(&mut tx_punish.input[0], satisfier)
.context("Failed to satisfy inputs with given signatures")?;
Ok(tx_punish)
}
}
impl Watchable for TxPunish {
fn id(&self) -> Txid {
self.inner.txid()
}
fn script(&self) -> Script {
self.watch_script.clone()
}
}