diff --git a/src/contracts.rs b/src/contracts.rs index b94e84b6..d51059e1 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -48,6 +48,7 @@ pub trait SwapCoin { fn get_contract_tx(&self) -> Transaction; fn get_contract_redeemscript(&self) -> Script; fn get_timelock_pubkey(&self) -> PublicKey; + fn get_timelock(&self) -> u16; fn get_hashlock_pubkey(&self) -> PublicKey; fn get_hashvalue(&self) -> Hash160; fn get_funding_amount(&self) -> u64; @@ -470,6 +471,10 @@ macro_rules! add_simple_swapcoin_get_functions { read_timelock_pubkey_from_contract(&self.contract_redeemscript).unwrap() } + fn get_timelock(&self) -> u16 { + read_locktime_from_contract(&self.contract_redeemscript).unwrap() + } + fn get_hashlock_pubkey(&self) -> PublicKey { read_hashlock_pubkey_from_contract(&self.contract_redeemscript).unwrap() } diff --git a/src/wallet_direct_send.rs b/src/wallet_direct_send.rs index 5947d6a8..c5f90b53 100644 --- a/src/wallet_direct_send.rs +++ b/src/wallet_direct_send.rs @@ -6,6 +6,7 @@ use bitcoin::{Address, Amount, OutPoint, Script, Transaction, TxIn, TxOut}; use bitcoincore_rpc::json::ListUnspentResultEntry; use bitcoincore_rpc::Client; +use crate::contracts::SwapCoin; use crate::error::Error; use crate::wallet_sync::{UTXOSpendInfo, Wallet, NETWORK}; @@ -139,9 +140,20 @@ impl Wallet { } } }; + + let sequence = match spend_info { + UTXOSpendInfo::TimelockContract { + ref swapcoin_multisig_redeemscript, + input_value: _, + } => self + .find_outgoing_swapcoin(swapcoin_multisig_redeemscript) + .unwrap() + .get_timelock() as u32, + _ => 0, + }; tx_inputs.push(TxIn { previous_output, - sequence: 0, + sequence, witness: Vec::new(), script_sig: Script::new(), }); @@ -154,6 +166,7 @@ impl Wallet { tx_inputs ); } + let dest_addr = match destination { Destination::Wallet => self.get_next_external_address(rpc)?, Destination::Address(a) => a, diff --git a/src/wallet_sync.rs b/src/wallet_sync.rs index 45af8bd6..f9e878fd 100644 --- a/src/wallet_sync.rs +++ b/src/wallet_sync.rs @@ -108,6 +108,7 @@ pub enum UTXOSpendInfo { }, TimelockContract { swapcoin_multisig_redeemscript: Script, + input_value: u64, }, } @@ -269,6 +270,31 @@ impl OutgoingSwapCoin { ); signed_contract_tx } + + fn sign_timelocked_transaction_input( + &self, + index: usize, + tx: &Transaction, + input: &mut TxIn, + input_value: u64, + ) { + let secp = Secp256k1::new(); + let sighash = secp256k1::Message::from_slice( + &SigHashCache::new(tx).signature_hash( + index, + &self.contract_redeemscript, + input_value, + SigHashType::All, + )[..], + ) + .unwrap(); + + let sig_timelock = secp.sign(&sighash, &self.timelock_privkey); + input.witness.push(sig_timelock.serialize_der().to_vec()); + input.witness[0].push(SigHashType::All as u8); + input.witness.push(Vec::new()); + input.witness.push(self.contract_redeemscript.to_bytes()); + } } pub trait WalletSwapCoin { @@ -750,6 +776,7 @@ impl Wallet { return if u.confirmations >= timelock.into() { Some(UTXOSpendInfo::TimelockContract { swapcoin_multisig_redeemscript: swapcoin.get_multisig_redeemscript(), + input_value: u.amount.as_sat(), }) } else { None @@ -1094,10 +1121,12 @@ impl Wallet { input.witness.push(pubkey.to_bytes()); } UTXOSpendInfo::TimelockContract { - swapcoin_multisig_redeemscript: _, - } => { - panic!("not implemented yet"); - } + swapcoin_multisig_redeemscript, + input_value, + } => self + .find_outgoing_swapcoin(&swapcoin_multisig_redeemscript) + .unwrap() + .sign_timelocked_transaction_input(ix, &tx_clone, &mut input, input_value), } } }