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.
This commit is contained in:
Philipp Hoenisch 2021-04-29 10:40:04 +10:00
parent d5c1b6693e
commit 1012e39527
No known key found for this signature in database
GPG Key ID: E5F8E74C672BC666
11 changed files with 101 additions and 30 deletions

View File

@ -37,7 +37,9 @@ use serde::{Deserialize, Serialize};
use sha2::Sha256; use sha2::Sha256;
use std::str::FromStr; use std::str::FromStr;
pub use crate::bitcoin::punish::ESTIMATED_WEIGHT as ESTIMATED_WEIGHT_TX_PUNISH;
pub use crate::bitcoin::redeem::ESTIMATED_WEIGHT as ESTIMATED_WEIGHT_TX_REDEEM; pub use crate::bitcoin::redeem::ESTIMATED_WEIGHT as ESTIMATED_WEIGHT_TX_REDEEM;
pub use crate::bitcoin::refund::ESTIMATED_WEIGHT as ESTIMATED_WEIGHT_TX_REFUND;
// TODO: Configurable tx-fee (note: parties have to agree prior to swapping) // TODO: Configurable tx-fee (note: parties have to agree prior to swapping)
// Current reasoning: // Current reasoning:

View File

@ -216,6 +216,7 @@ impl TxCancel {
&self, &self,
spend_address: &Address, spend_address: &Address,
sequence: Option<PunishTimelock>, sequence: Option<PunishTimelock>,
spending_fee: Amount,
) -> Transaction { ) -> Transaction {
let previous_output = self.as_outpoint(); let previous_output = self.as_outpoint();
@ -227,7 +228,7 @@ impl TxCancel {
}; };
let tx_out = TxOut { let tx_out = TxOut {
value: self.amount().as_sat() - TX_FEE, value: self.amount().as_sat() - spending_fee.as_sat(),
script_pubkey: spend_address.script_pubkey(), script_pubkey: spend_address.script_pubkey(),
}; };

View File

@ -136,6 +136,7 @@ impl TxLock {
&self, &self,
spend_address: &Address, spend_address: &Address,
sequence: Option<u32>, sequence: Option<u32>,
spending_fee: Amount,
) -> Transaction { ) -> Transaction {
let previous_output = self.as_outpoint(); let previous_output = self.as_outpoint();
@ -147,7 +148,8 @@ impl TxLock {
}; };
let tx_out = TxOut { let tx_out = TxOut {
value: self.inner.clone().extract_tx().output[self.lock_output_vout()].value - TX_FEE, value: self.inner.clone().extract_tx().output[self.lock_output_vout()].value
- spending_fee.as_sat(),
script_pubkey: spend_address.script_pubkey(), script_pubkey: spend_address.script_pubkey(),
}; };

View File

@ -1,5 +1,5 @@
use crate::bitcoin::wallet::Watchable; use crate::bitcoin::wallet::Watchable;
use crate::bitcoin::{self, Address, PunishTimelock, Transaction, TxCancel, Txid}; use crate::bitcoin::{self, Address, Amount, PunishTimelock, Transaction, TxCancel, Txid};
use ::bitcoin::util::bip143::SigHashCache; use ::bitcoin::util::bip143::SigHashCache;
use ::bitcoin::{SigHash, SigHashType}; use ::bitcoin::{SigHash, SigHashType};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
@ -7,6 +7,9 @@ use bdk::bitcoin::Script;
use miniscript::{Descriptor, DescriptorTrait}; use miniscript::{Descriptor, DescriptorTrait};
use std::collections::HashMap; use std::collections::HashMap;
// TODO take real tx weight from past transaction
pub const ESTIMATED_WEIGHT: usize = 10_000;
#[derive(Debug)] #[derive(Debug)]
pub struct TxPunish { pub struct TxPunish {
inner: Transaction, inner: Transaction,
@ -20,8 +23,10 @@ impl TxPunish {
tx_cancel: &TxCancel, tx_cancel: &TxCancel,
punish_address: &Address, punish_address: &Address,
punish_timelock: PunishTimelock, punish_timelock: PunishTimelock,
spending_fee: Amount,
) -> Self { ) -> Self {
let tx_punish = tx_cancel.build_spend_transaction(punish_address, Some(punish_timelock)); let tx_punish =
tx_cancel.build_spend_transaction(punish_address, Some(punish_timelock), spending_fee);
let digest = SigHashCache::new(&tx_punish).signature_hash( let digest = SigHashCache::new(&tx_punish).signature_hash(
0, // Only one input: cancel transaction 0, // Only one input: cancel transaction

View File

@ -1,7 +1,7 @@
use crate::bitcoin::wallet::Watchable; use crate::bitcoin::wallet::Watchable;
use crate::bitcoin::{ use crate::bitcoin::{
verify_sig, Address, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey, TooManyInputs, verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey,
Transaction, TxCancel, TooManyInputs, Transaction, TxCancel,
}; };
use crate::{bitcoin, monero}; use crate::{bitcoin, monero};
use ::bitcoin::util::bip143::SigHashCache; use ::bitcoin::util::bip143::SigHashCache;
@ -11,6 +11,9 @@ use ecdsa_fun::Signature;
use miniscript::{Descriptor, DescriptorTrait}; use miniscript::{Descriptor, DescriptorTrait};
use std::collections::HashMap; use std::collections::HashMap;
// TODO take real tx weight from past transaction
pub const ESTIMATED_WEIGHT: usize = 10_000;
#[derive(Debug)] #[derive(Debug)]
pub struct TxRefund { pub struct TxRefund {
inner: Transaction, inner: Transaction,
@ -20,10 +23,10 @@ pub struct TxRefund {
} }
impl TxRefund { impl TxRefund {
pub fn new(tx_cancel: &TxCancel, refund_address: &Address) -> Self { pub fn new(tx_cancel: &TxCancel, refund_address: &Address, spending_fee: Amount) -> Self {
let tx_punish = tx_cancel.build_spend_transaction(refund_address, None); let tx_refund = tx_cancel.build_spend_transaction(refund_address, None, spending_fee);
let digest = SigHashCache::new(&tx_punish).signature_hash( let digest = SigHashCache::new(&tx_refund).signature_hash(
0, // Only one input: cancel transaction 0, // Only one input: cancel transaction
&tx_cancel.output_descriptor.script_code(), &tx_cancel.output_descriptor.script_code(),
tx_cancel.amount().as_sat(), tx_cancel.amount().as_sat(),
@ -31,7 +34,7 @@ impl TxRefund {
); );
Self { Self {
inner: tx_punish, inner: tx_refund,
digest, digest,
cancel_output_descriptor: tx_cancel.output_descriptor.clone(), cancel_output_descriptor: tx_cancel.output_descriptor.clone(),
watch_script: refund_address.script_pubkey(), watch_script: refund_address.script_pubkey(),

View File

@ -28,6 +28,8 @@ pub struct Message0 {
dleq_proof_s_b: CrossCurveDLEQProof, dleq_proof_s_b: CrossCurveDLEQProof,
v_b: monero::PrivateViewKey, v_b: monero::PrivateViewKey,
refund_address: bitcoin::Address, refund_address: bitcoin::Address,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_refund_fee: bitcoin::Amount,
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -41,6 +43,8 @@ pub struct Message1 {
punish_address: bitcoin::Address, punish_address: bitcoin::Address,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")] #[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_punish_fee: bitcoin::Amount,
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]

View File

@ -1,6 +1,6 @@
use crate::bitcoin::{ use crate::bitcoin::{
current_epoch, CancelTimelock, ExpiredTimelocks, PunishTimelock, TxCancel, TxPunish, TxRefund, current_epoch, CancelTimelock, ExpiredTimelocks, PunishTimelock, TxCancel, TxPunish, TxRefund,
ESTIMATED_WEIGHT_TX_REDEEM, ESTIMATED_WEIGHT_TX_PUNISH, ESTIMATED_WEIGHT_TX_REDEEM,
}; };
use crate::env::Config; use crate::env::Config;
use crate::monero::wallet::{TransferRequest, WatchRequest}; use crate::monero::wallet::{TransferRequest, WatchRequest};
@ -110,6 +110,7 @@ pub struct State0 {
redeem_address: bitcoin::Address, redeem_address: bitcoin::Address,
punish_address: bitcoin::Address, punish_address: bitcoin::Address,
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
tx_punish_fee: bitcoin::Amount,
} }
impl State0 { impl State0 {
@ -147,6 +148,7 @@ impl State0 {
cancel_timelock: env_config.bitcoin_cancel_timelock, cancel_timelock: env_config.bitcoin_cancel_timelock,
punish_timelock: env_config.bitcoin_punish_timelock, punish_timelock: env_config.bitcoin_punish_timelock,
tx_redeem_fee: bitcoin_wallet.estimate_fee(ESTIMATED_WEIGHT_TX_REDEEM), tx_redeem_fee: bitcoin_wallet.estimate_fee(ESTIMATED_WEIGHT_TX_REDEEM),
tx_punish_fee: bitcoin_wallet.estimate_fee(ESTIMATED_WEIGHT_TX_PUNISH),
}) })
} }
@ -187,6 +189,8 @@ impl State0 {
redeem_address: self.redeem_address, redeem_address: self.redeem_address,
punish_address: self.punish_address, punish_address: self.punish_address,
tx_redeem_fee: self.tx_redeem_fee, tx_redeem_fee: self.tx_redeem_fee,
tx_punish_fee: self.tx_punish_fee,
tx_refund_fee: msg.tx_refund_fee,
})) }))
} }
} }
@ -211,6 +215,8 @@ pub struct State1 {
redeem_address: bitcoin::Address, redeem_address: bitcoin::Address,
punish_address: bitcoin::Address, punish_address: bitcoin::Address,
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
tx_punish_fee: bitcoin::Amount,
tx_refund_fee: bitcoin::Amount,
} }
impl State1 { impl State1 {
@ -224,6 +230,7 @@ impl State1 {
redeem_address: self.redeem_address.clone(), redeem_address: self.redeem_address.clone(),
punish_address: self.punish_address.clone(), punish_address: self.punish_address.clone(),
tx_redeem_fee: self.tx_redeem_fee, tx_redeem_fee: self.tx_redeem_fee,
tx_punish_fee: self.tx_punish_fee,
} }
} }
@ -247,6 +254,8 @@ impl State1 {
punish_address: self.punish_address, punish_address: self.punish_address,
tx_lock, tx_lock,
tx_redeem_fee: self.tx_redeem_fee, tx_redeem_fee: self.tx_redeem_fee,
tx_punish_fee: self.tx_punish_fee,
tx_refund_fee: self.tx_refund_fee,
}) })
} }
} }
@ -268,6 +277,8 @@ pub struct State2 {
punish_address: bitcoin::Address, punish_address: bitcoin::Address,
tx_lock: bitcoin::TxLock, tx_lock: bitcoin::TxLock,
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
tx_punish_fee: bitcoin::Amount,
tx_refund_fee: bitcoin::Amount,
} }
impl State2 { impl State2 {
@ -275,7 +286,8 @@ impl State2 {
let tx_cancel = let tx_cancel =
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B); bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address); let tx_refund =
bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee);
// Alice encsigns the refund transaction(bitcoin) digest with Bob's monero // Alice encsigns the refund transaction(bitcoin) digest with Bob's monero
// pubkey(S_b). The refund transaction spends the output of // pubkey(S_b). The refund transaction spends the output of
// tx_lock_bitcoin to Bob's refund address. // tx_lock_bitcoin to Bob's refund address.
@ -295,8 +307,12 @@ impl State2 {
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B); bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
bitcoin::verify_sig(&self.B, &tx_cancel.digest(), &msg.tx_cancel_sig) bitcoin::verify_sig(&self.B, &tx_cancel.digest(), &msg.tx_cancel_sig)
.context("Failed to verify cancel transaction")?; .context("Failed to verify cancel transaction")?;
let tx_punish = let tx_punish = bitcoin::TxPunish::new(
bitcoin::TxPunish::new(&tx_cancel, &self.punish_address, self.punish_timelock); &tx_cancel,
&self.punish_address,
self.punish_timelock,
self.tx_punish_fee,
);
bitcoin::verify_sig(&self.B, &tx_punish.digest(), &msg.tx_punish_sig) bitcoin::verify_sig(&self.B, &tx_punish.digest(), &msg.tx_punish_sig)
.context("Failed to verify punish transaction")?; .context("Failed to verify punish transaction")?;
@ -318,6 +334,8 @@ impl State2 {
tx_punish_sig_bob: msg.tx_punish_sig, tx_punish_sig_bob: msg.tx_punish_sig,
tx_cancel_sig_bob: msg.tx_cancel_sig, tx_cancel_sig_bob: msg.tx_cancel_sig,
tx_redeem_fee: self.tx_redeem_fee, tx_redeem_fee: self.tx_redeem_fee,
tx_punish_fee: self.tx_punish_fee,
tx_refund_fee: self.tx_refund_fee,
}) })
} }
} }
@ -343,6 +361,10 @@ pub struct State3 {
tx_cancel_sig_bob: bitcoin::Signature, tx_cancel_sig_bob: bitcoin::Signature,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")] #[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_punish_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_refund_fee: bitcoin::Amount,
} }
impl State3 { impl State3 {
@ -399,7 +421,7 @@ impl State3 {
} }
pub fn tx_refund(&self) -> TxRefund { pub fn tx_refund(&self) -> TxRefund {
bitcoin::TxRefund::new(&self.tx_cancel(), &self.refund_address) bitcoin::TxRefund::new(&self.tx_cancel(), &self.refund_address, self.tx_refund_fee)
} }
pub fn extract_monero_private_key( pub fn extract_monero_private_key(
@ -440,6 +462,7 @@ impl State3 {
&self.tx_cancel(), &self.tx_cancel(),
&self.punish_address, &self.punish_address,
self.punish_timelock, self.punish_timelock,
self.tx_punish_fee,
) )
} }
} }

View File

@ -83,6 +83,7 @@ pub struct State0 {
punish_timelock: PunishTimelock, punish_timelock: PunishTimelock,
refund_address: bitcoin::Address, refund_address: bitcoin::Address,
min_monero_confirmations: u64, min_monero_confirmations: u64,
tx_refund_fee: bitcoin::Amount,
} }
impl State0 { impl State0 {
@ -96,6 +97,7 @@ impl State0 {
punish_timelock: PunishTimelock, punish_timelock: PunishTimelock,
refund_address: bitcoin::Address, refund_address: bitcoin::Address,
min_monero_confirmations: u64, min_monero_confirmations: u64,
tx_refund_fee: bitcoin::Amount,
) -> Self { ) -> Self {
let b = bitcoin::SecretKey::new_random(rng); let b = bitcoin::SecretKey::new_random(rng);
@ -120,6 +122,7 @@ impl State0 {
punish_timelock, punish_timelock,
refund_address, refund_address,
min_monero_confirmations, min_monero_confirmations,
tx_refund_fee,
} }
} }
@ -132,6 +135,7 @@ impl State0 {
dleq_proof_s_b: self.dleq_proof_s_b.clone(), dleq_proof_s_b: self.dleq_proof_s_b.clone(),
v_b: self.v_b, v_b: self.v_b,
refund_address: self.refund_address.clone(), refund_address: self.refund_address.clone(),
tx_refund_fee: self.tx_refund_fee,
} }
} }
@ -170,6 +174,8 @@ impl State0 {
tx_lock, tx_lock,
min_monero_confirmations: self.min_monero_confirmations, min_monero_confirmations: self.min_monero_confirmations,
tx_redeem_fee: msg.tx_redeem_fee, tx_redeem_fee: msg.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
tx_punish_fee: msg.tx_punish_fee,
}) })
} }
} }
@ -191,6 +197,8 @@ pub struct State1 {
tx_lock: bitcoin::TxLock, tx_lock: bitcoin::TxLock,
min_monero_confirmations: u64, min_monero_confirmations: u64,
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
tx_refund_fee: bitcoin::Amount,
tx_punish_fee: bitcoin::Amount,
} }
impl State1 { impl State1 {
@ -202,7 +210,8 @@ impl State1 {
pub fn receive(self, msg: Message3) -> Result<State2> { pub fn receive(self, msg: Message3) -> Result<State2> {
let tx_cancel = TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public()); let tx_cancel = TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address); let tx_refund =
bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee);
bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?; bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?;
bitcoin::verify_encsig( bitcoin::verify_encsig(
@ -230,6 +239,8 @@ impl State1 {
tx_refund_encsig: msg.tx_refund_encsig, tx_refund_encsig: msg.tx_refund_encsig,
min_monero_confirmations: self.min_monero_confirmations, min_monero_confirmations: self.min_monero_confirmations,
tx_redeem_fee: self.tx_redeem_fee, tx_redeem_fee: self.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
tx_punish_fee: self.tx_punish_fee,
}) })
} }
} }
@ -254,14 +265,22 @@ pub struct State2 {
min_monero_confirmations: u64, min_monero_confirmations: u64,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")] #[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_punish_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_refund_fee: bitcoin::Amount,
} }
impl State2 { impl State2 {
pub fn next_message(&self) -> Message4 { pub fn next_message(&self) -> Message4 {
let tx_cancel = TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public()); let tx_cancel = TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
let tx_cancel_sig = self.b.sign(tx_cancel.digest()); let tx_cancel_sig = self.b.sign(tx_cancel.digest());
let tx_punish = let tx_punish = bitcoin::TxPunish::new(
bitcoin::TxPunish::new(&tx_cancel, &self.punish_address, self.punish_timelock); &tx_cancel,
&self.punish_address,
self.punish_timelock,
self.tx_punish_fee,
);
let tx_punish_sig = self.b.sign(tx_punish.digest()); let tx_punish_sig = self.b.sign(tx_punish.digest());
Message4 { Message4 {
@ -289,6 +308,7 @@ impl State2 {
tx_refund_encsig: self.tx_refund_encsig, tx_refund_encsig: self.tx_refund_encsig,
min_monero_confirmations: self.min_monero_confirmations, min_monero_confirmations: self.min_monero_confirmations,
tx_redeem_fee: self.tx_redeem_fee, tx_redeem_fee: self.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
}, },
self.tx_lock, self.tx_lock,
)) ))
@ -314,6 +334,8 @@ pub struct State3 {
min_monero_confirmations: u64, min_monero_confirmations: u64,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")] #[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_refund_fee: bitcoin::Amount,
} }
impl State3 { impl State3 {
@ -347,6 +369,7 @@ impl State3 {
tx_refund_encsig: self.tx_refund_encsig, tx_refund_encsig: self.tx_refund_encsig,
monero_wallet_restore_blockheight, monero_wallet_restore_blockheight,
tx_redeem_fee: self.tx_redeem_fee, tx_redeem_fee: self.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
} }
} }
@ -361,6 +384,7 @@ impl State3 {
tx_lock: self.tx_lock.clone(), tx_lock: self.tx_lock.clone(),
tx_cancel_sig_a: self.tx_cancel_sig_a.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a.clone(),
tx_refund_encsig: self.tx_refund_encsig.clone(), tx_refund_encsig: self.tx_refund_encsig.clone(),
tx_refund_fee: self.tx_refund_fee,
} }
} }
@ -403,6 +427,8 @@ pub struct State4 {
monero_wallet_restore_blockheight: BlockHeight, monero_wallet_restore_blockheight: BlockHeight,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")] #[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount, tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_refund_fee: bitcoin::Amount,
} }
impl State4 { impl State4 {
@ -467,6 +493,7 @@ impl State4 {
tx_lock: self.tx_lock, tx_lock: self.tx_lock,
tx_cancel_sig_a: self.tx_cancel_sig_a, tx_cancel_sig_a: self.tx_cancel_sig_a,
tx_refund_encsig: self.tx_refund_encsig, tx_refund_encsig: self.tx_refund_encsig,
tx_refund_fee: self.tx_refund_fee,
} }
} }
} }
@ -505,6 +532,8 @@ pub struct State6 {
tx_lock: bitcoin::TxLock, tx_lock: bitcoin::TxLock,
tx_cancel_sig_a: Signature, tx_cancel_sig_a: Signature,
tx_refund_encsig: bitcoin::EncryptedSignature, tx_refund_encsig: bitcoin::EncryptedSignature,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
pub tx_refund_fee: bitcoin::Amount,
} }
impl State6 { impl State6 {
@ -551,7 +580,8 @@ impl State6 {
pub async fn refund_btc(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result<()> { pub async fn refund_btc(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result<()> {
let tx_cancel = let tx_cancel =
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public()); bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address); let tx_refund =
bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee);
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default(); let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();

View File

@ -66,6 +66,7 @@ async fn next_state(
Ok(match state { Ok(match state {
BobState::Started { btc_amount } => { BobState::Started { btc_amount } => {
let bitcoin_refund_address = bitcoin_wallet.new_address().await?; let bitcoin_refund_address = bitcoin_wallet.new_address().await?;
let tx_refund_fee = bitcoin_wallet.estimate_fee(bitcoin::ESTIMATED_WEIGHT_TX_REDEEM);
let state2 = request_price_and_setup( let state2 = request_price_and_setup(
swap_id, swap_id,
@ -73,6 +74,7 @@ async fn next_state(
event_loop_handle, event_loop_handle,
env_config, env_config,
bitcoin_refund_address, bitcoin_refund_address,
tx_refund_fee,
) )
.await?; .await?;
@ -268,6 +270,7 @@ pub async fn request_price_and_setup(
event_loop_handle: &mut EventLoopHandle, event_loop_handle: &mut EventLoopHandle,
env_config: &Config, env_config: &Config,
bitcoin_refund_address: bitcoin::Address, bitcoin_refund_address: bitcoin::Address,
tx_refund_fee: bitcoin::Amount,
) -> Result<bob::state::State2> { ) -> Result<bob::state::State2> {
let xmr = event_loop_handle.request_spot_price(btc).await?; let xmr = event_loop_handle.request_spot_price(btc).await?;
@ -282,6 +285,7 @@ pub async fn request_price_and_setup(
env_config.bitcoin_punish_timelock, env_config.bitcoin_punish_timelock,
bitcoin_refund_address, bitcoin_refund_address,
env_config.monero_finality_confirmations, env_config.monero_finality_confirmations,
tx_refund_fee,
); );
let state2 = event_loop_handle.execution_setup(state0).await?; let state2 = event_loop_handle.execution_setup(state0).await?;

View File

@ -10,7 +10,7 @@ pub const DATADIR: &str = "/home/bdk";
// Bitcoin regtest TX fee. The fee itself does not matter for our tests. It just // Bitcoin regtest TX fee. The fee itself does not matter for our tests. It just
// has to be static so that we can assert on the amounts. // has to be static so that we can assert on the amounts.
pub const TX_FEE: u64 = 10_000; pub const TX_FEE: u64 = 15_000;
#[derive(Debug)] #[derive(Debug)]
pub struct Bitcoind { pub struct Bitcoind {

View File

@ -1,6 +1,7 @@
mod bitcoind; mod bitcoind;
mod electrs; mod electrs;
use crate::harness::bitcoind::TX_FEE;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use async_trait::async_trait; use async_trait::async_trait;
use bitcoin_harness::{BitcoindRpcApi, Client}; use bitcoin_harness::{BitcoindRpcApi, Client};
@ -39,6 +40,8 @@ use uuid::Uuid;
// bitcoin::ESTIMATED_WEIGHT_TX_REDEEM changes. // bitcoin::ESTIMATED_WEIGHT_TX_REDEEM changes.
// TODO: see if there is a better way. // TODO: see if there is a better way.
const TX_REDEEM_FEE: u64 = 12500; const TX_REDEEM_FEE: u64 = 12500;
const TX_REFUND_FEE: u64 = 12500;
const TX_CANCEL_FEE: u64 = TX_FEE;
pub async fn setup_test<T, F, C>(_config: C, testfn: T) pub async fn setup_test<T, F, C>(_config: C, testfn: T)
where where
@ -636,19 +639,13 @@ impl TestContext {
let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap(); let btc_balance_after_swap = self.bob_bitcoin_wallet.balance().await.unwrap();
let alice_submitted_cancel = btc_balance_after_swap let bob_cancelled_and_refunded = btc_balance_after_swap
== self.bob_starting_balances.btc == self.bob_starting_balances.btc
- lock_tx_bitcoin_fee - lock_tx_bitcoin_fee
- bitcoin::Amount::from_sat(bitcoind::TX_FEE); - bitcoin::Amount::from_sat(TX_CANCEL_FEE)
- bitcoin::Amount::from_sat(TX_REFUND_FEE);
let bob_submitted_cancel = btc_balance_after_swap assert!(bob_cancelled_and_refunded);
== self.bob_starting_balances.btc
- lock_tx_bitcoin_fee
- bitcoin::Amount::from_sat(2 * bitcoind::TX_FEE);
// The cancel tx can be submitted by both Alice and Bob.
// Since we cannot be sure who submitted it we have to assert accordingly
assert!(alice_submitted_cancel || bob_submitted_cancel);
assert_eventual_balance( assert_eventual_balance(
self.bob_monero_wallet.as_ref(), self.bob_monero_wallet.as_ref(),