diff --git a/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs b/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs index f441b5f..2b32681 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs @@ -119,10 +119,96 @@ pub fn build_escrow_transaction_output_descriptor( } // pub fn assemble_escrow_psbts( -// coordinator: &Coordinator, -// escrow_data: &EscrowPsbtConstructionData, -// coordinator_pk: &XOnlyPublicKey, -// ) -> Result<()> { -// panic!("Implement wallet.build_escrow_psbt()"); -// Ok(()) -// } +impl CoordinatorWallet { + pub async fn create_escrow_psbt( + &self, + db: &Arc, + taker_psbt_request: &OfferPsbtRequest, + ) -> Result { + let trade_id = &taker_psbt_request.offer.offer_id_hex.clone(); + let maker_psbt_input_data = db.fetch_maker_escrow_psbt_data(trade_id).await?; + let taker_psbt_input_data = EscrowPsbtConstructionData { + taproot_xonly_pubkey_hex: taker_psbt_request.trade_data.taproot_pubkey_hex.clone(), + escrow_input_utxos: csv_hex_to_bdk_input( + &taker_psbt_request.trade_data.bdk_psbt_inputs_hex_csv, + )?, + change_address: Address::from_str( + &taker_psbt_request.trade_data.client_change_address, + )? + .assume_checked(), + musig_pubkey_compressed_hex: taker_psbt_request.trade_data.musig_pubkey_hex.clone(), + }; + + let coordinator_escrow_pk = self.get_coordinator_taproot_pk().await?; + let escrow_output_descriptor = build_escrow_transaction_output_descriptor( + &maker_psbt_input_data, + &taker_psbt_input_data, + &coordinator_escrow_pk, + )?; + + let escrow_coordinator_fee_address = + Address::from_str(&self.get_new_address().await?)?.assume_checked(); + + let (escrow_amount_maker_sat, escrow_amount_taker_sat, escrow_fee_sat_per_participant) = db + .get_escrow_tx_amounts(trade_id, self.coordinator_feerate) + .await?; + + let (escrow_psbt, details) = { + // maybe we can generate a address/taproot pk directly from the descriptor without a new wallet? + let temp_wallet = Wallet::new( + &escrow_output_descriptor, + None, + bitcoin::Network::Regtest, + MemoryDatabase::new(), + )?; + let escrow_address = temp_wallet + .get_address(bdk::wallet::AddressIndex::New)? + .address; + + // using absolute fee for now, in production we should come up with a way to determine the tx weight + // upfront and substract the fee from the change outputs + let tx_fee_abs = 10000; + + let change_amount_maker = maker_psbt_input_data.input_sum()? + - (escrow_amount_maker_sat + escrow_fee_sat_per_participant + tx_fee_abs / 2); + let change_amount_taker = taker_psbt_input_data.input_sum()? + - (escrow_amount_taker_sat + escrow_fee_sat_per_participant + tx_fee_abs / 2); + + let amount_escrow = escrow_amount_maker_sat + escrow_amount_taker_sat; + let mut builder = temp_wallet.build_tx(); + builder + .manually_selected_only() + .add_recipient(escrow_address.script_pubkey(), amount_escrow) + .add_recipient( + escrow_coordinator_fee_address.script_pubkey(), + escrow_fee_sat_per_participant * 2, + ) + .add_recipient( + maker_psbt_input_data.change_address.script_pubkey(), + change_amount_maker, + ) + .add_recipient( + taker_psbt_input_data.change_address.script_pubkey(), + change_amount_taker, + ) + .fee_absolute(tx_fee_abs); + for input in maker_psbt_input_data.escrow_input_utxos.iter() { + // satisfaction weight 66 bytes for schnorr sig + opcode + sighash for keyspend. This is a hack? + builder.add_foreign_utxo(input.utxo, input.psbt_input.clone(), 264)?; + } + for input in taker_psbt_input_data.escrow_input_utxos.iter() { + builder.add_foreign_utxo(input.utxo, input.psbt_input.clone(), 264)?; + } + builder.finish()? + }; + + Ok(EscrowPsbt { + escrow_psbt_hex: escrow_psbt.to_string(), + escrow_output_descriptor, + coordinator_xonly_escrow_pk: coordinator_escrow_pk.to_string(), + escrow_amount_maker_sat, + escrow_amount_taker_sat, + escrow_fee_sat_per_participant, + }) + } +} diff --git a/taptrade-cli-demo/coordinator/src/wallet/mod.rs b/taptrade-cli-demo/coordinator/src/wallet/mod.rs index 8013bf3..5f4b349 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/mod.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/mod.rs @@ -244,98 +244,6 @@ impl CoordinatorWallet { Ok(()) } - pub async fn create_escrow_psbt( - &self, - db: &Arc, - taker_psbt_request: &OfferPsbtRequest, - ) -> Result { - let trade_id = &taker_psbt_request.offer.offer_id_hex.clone(); - let maker_psbt_input_data = db.fetch_maker_escrow_psbt_data(trade_id).await?; - let taker_psbt_input_data = EscrowPsbtConstructionData { - taproot_xonly_pubkey_hex: taker_psbt_request.trade_data.taproot_pubkey_hex.clone(), - escrow_input_utxos: csv_hex_to_bdk_input( - &taker_psbt_request.trade_data.bdk_psbt_inputs_hex_csv, - )?, - change_address: Address::from_str( - &taker_psbt_request.trade_data.client_change_address, - )? - .assume_checked(), - musig_pubkey_compressed_hex: taker_psbt_request.trade_data.musig_pubkey_hex.clone(), - }; - - let coordinator_escrow_pk = self.get_coordinator_taproot_pk().await?; - let escrow_output_descriptor = build_escrow_transaction_output_descriptor( - &maker_psbt_input_data, - &taker_psbt_input_data, - &coordinator_escrow_pk, - )?; - - let escrow_coordinator_fee_address = - Address::from_str(&self.get_new_address().await?)?.assume_checked(); - - let (escrow_amount_maker_sat, escrow_amount_taker_sat, escrow_fee_sat_per_participant) = db - .get_escrow_tx_amounts(trade_id, self.coordinator_feerate) - .await?; - - let (escrow_psbt, details) = { - // maybe we can generate a address/taproot pk directly from the descriptor without a new wallet? - let temp_wallet = Wallet::new( - &escrow_output_descriptor, - None, - bitcoin::Network::Regtest, - MemoryDatabase::new(), - )?; - let escrow_address = temp_wallet - .get_address(bdk::wallet::AddressIndex::New)? - .address; - - // using absolute fee for now, in production we should come up with a way to determine the tx weight - // upfront and substract the fee from the change outputs - let tx_fee_abs = 10000; - - let change_amount_maker = maker_psbt_input_data.input_sum()? - - (escrow_amount_maker_sat + escrow_fee_sat_per_participant + tx_fee_abs / 2); - let change_amount_taker = taker_psbt_input_data.input_sum()? - - (escrow_amount_taker_sat + escrow_fee_sat_per_participant + tx_fee_abs / 2); - - let amount_escrow = escrow_amount_maker_sat + escrow_amount_taker_sat; - let mut builder = temp_wallet.build_tx(); - builder - .manually_selected_only() - .add_recipient(escrow_address.script_pubkey(), amount_escrow) - .add_recipient( - escrow_coordinator_fee_address.script_pubkey(), - escrow_fee_sat_per_participant * 2, - ) - .add_recipient( - maker_psbt_input_data.change_address.script_pubkey(), - change_amount_maker, - ) - .add_recipient( - taker_psbt_input_data.change_address.script_pubkey(), - change_amount_taker, - ) - .fee_absolute(tx_fee_abs); - for input in maker_psbt_input_data.escrow_input_utxos.iter() { - // satisfaction weight 66 bytes for schnorr sig + opcode + sighash for keyspend. This is a hack? - builder.add_foreign_utxo(input.utxo, input.psbt_input.clone(), 264)?; - } - for input in taker_psbt_input_data.escrow_input_utxos.iter() { - builder.add_foreign_utxo(input.utxo, input.psbt_input.clone(), 264)?; - } - builder.finish()? - }; - - Ok(EscrowPsbt { - escrow_psbt_hex: escrow_psbt.to_string(), - escrow_output_descriptor, - coordinator_xonly_escrow_pk: coordinator_escrow_pk.to_string(), - escrow_amount_maker_sat, - escrow_amount_taker_sat, - escrow_fee_sat_per_participant, - }) - } - pub async fn get_coordinator_taproot_pk(&self) -> Result { let wallet = self.wallet.lock().await; let address = wallet.get_address(bdk::wallet::AddressIndex::New)?;