From f45703aa63351b82925729f2b13681d2ec10171d Mon Sep 17 00:00:00 2001 From: f321x Date: Thu, 1 Aug 2024 19:01:29 +0200 Subject: [PATCH] finish improvised psbt assembly coordinator side. --- taptrade-cli-demo/coordinator/Cargo.lock | 10 ++ taptrade-cli-demo/coordinator/Cargo.toml | 1 + .../coordinator/src/communication/api.rs | 1 + .../coordinator/src/coordinator/mod.rs | 3 +- .../coordinator/src/database/mod.rs | 66 +++++++++----- taptrade-cli-demo/coordinator/src/main.rs | 2 +- .../coordinator/src/wallet/escrow_psbt.rs | 54 +++++++---- .../coordinator/src/wallet/mod.rs | 91 ++++++++++++++++--- .../src/wallet/{utils.rs => wallet_utils.rs} | 22 ++++- .../trader/src/communication/api.rs | 1 + .../trader/src/communication/mod.rs | 68 +++++++------- .../trader/src/trading/maker_utils.rs | 24 +++-- taptrade-cli-demo/trader/src/trading/mod.rs | 8 +- taptrade-cli-demo/trader/src/trading/utils.rs | 2 + taptrade-cli-demo/trader/src/wallet/mod.rs | 15 ++- 15 files changed, 266 insertions(+), 102 deletions(-) rename taptrade-cli-demo/coordinator/src/wallet/{utils.rs => wallet_utils.rs} (72%) diff --git a/taptrade-cli-demo/coordinator/Cargo.lock b/taptrade-cli-demo/coordinator/Cargo.lock index 4eca7ed..6cf367f 100644 --- a/taptrade-cli-demo/coordinator/Cargo.lock +++ b/taptrade-cli-demo/coordinator/Cargo.lock @@ -288,6 +288,15 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitcoin" version = "0.30.2" @@ -465,6 +474,7 @@ dependencies = [ "anyhow", "axum", "bdk", + "bincode", "bitcoin 0.32.2", "dotenvy", "env_logger", diff --git a/taptrade-cli-demo/coordinator/Cargo.toml b/taptrade-cli-demo/coordinator/Cargo.toml index 30497ae..1c84e09 100644 --- a/taptrade-cli-demo/coordinator/Cargo.toml +++ b/taptrade-cli-demo/coordinator/Cargo.toml @@ -27,6 +27,7 @@ env_logger = "0.11" sha2 = "0.10" validator = { version = "0.18", features = ["derive"] } musig2 = "0.0.11" +bincode = "1.3.3" [profile.release] lto = true diff --git a/taptrade-cli-demo/coordinator/src/communication/api.rs b/taptrade-cli-demo/coordinator/src/communication/api.rs index 94de63f..a06e14c 100644 --- a/taptrade-cli-demo/coordinator/src/communication/api.rs +++ b/taptrade-cli-demo/coordinator/src/communication/api.rs @@ -64,6 +64,7 @@ pub struct PublicOffers { #[derive(Serialize, Debug, Deserialize)] pub struct OfferTakenResponse { + pub escrow_psbt_hex: String, pub escrow_output_descriptor: String, pub escrow_tx_fee_address: String, pub escrow_amount_maker_sat: u64, diff --git a/taptrade-cli-demo/coordinator/src/coordinator/mod.rs b/taptrade-cli-demo/coordinator/src/coordinator/mod.rs index f89c574..2c3e7b3 100755 --- a/taptrade-cli-demo/coordinator/src/coordinator/mod.rs +++ b/taptrade-cli-demo/coordinator/src/coordinator/mod.rs @@ -133,7 +133,7 @@ pub async fn handle_taker_bond( } debug!("\nTaker bond validation successful"); - let escrow_output_data = match wallet.get_escrow_psbt(database, &payload).await { + let escrow_output_data = match wallet.create_escrow_psbt(database, &payload).await { Ok(escrow_output_data) => escrow_output_data, Err(e) => { return Err(BondError::CoordinatorError(e.to_string())); @@ -148,6 +148,7 @@ pub async fn handle_taker_bond( } Ok(OfferTakenResponse { + escrow_psbt_hex: escrow_output_data.escrow_psbt_hex, escrow_output_descriptor: escrow_output_data.escrow_output_descriptor, escrow_tx_fee_address: escrow_output_data.escrow_tx_fee_address, escrow_amount_maker_sat: escrow_output_data.escrow_amount_maker_sat, diff --git a/taptrade-cli-demo/coordinator/src/database/mod.rs b/taptrade-cli-demo/coordinator/src/database/mod.rs index dad2684..c1629a1 100644 --- a/taptrade-cli-demo/coordinator/src/database/mod.rs +++ b/taptrade-cli-demo/coordinator/src/database/mod.rs @@ -5,8 +5,10 @@ use anyhow::Context; use futures_util::StreamExt; use super::*; +use bdk::bitcoin::address::Address; use sqlx::{sqlite::SqlitePoolOptions, Pool, Row, Sqlite}; use std::env; +use std::str::FromStr; #[derive(Clone, Debug)] pub struct CoordinatorDB { @@ -692,29 +694,29 @@ impl CoordinatorDB { Ok(winner_robohash) } - pub async fn fetch_escrow_tx_payout_data( - &self, - offer_id: &str, - ) -> Result { - let row = sqlx::query("SELECT taproot_xonly_pubkey_hex_maker, taproot_xonly_pubkey_hex_taker, musig_pubkey_compressed_hex_maker, musig_pubkey_compressed_hex_taker FROM taken_offers WHERE offer_id = ?") - .bind(offer_id) - .fetch_one(&*self.db_pool) - .await?; + // pub async fn fetch_escrow_tx_payout_data( + // &self, + // offer_id: &str, + // ) -> Result { + // let row = sqlx::query("SELECT taproot_xonly_pubkey_hex_maker, taproot_xonly_pubkey_hex_taker, musig_pubkey_compressed_hex_maker, musig_pubkey_compressed_hex_taker FROM taken_offers WHERE offer_id = ?") + // .bind(offer_id) + // .fetch_one(&*self.db_pool) + // .await?; - let taproot_xonly_pubkey_hex_maker: String = row.get("taproot_xonly_pubkey_hex_maker"); - let taproot_xonly_pubkey_hex_taker: String = row.get("taproot_xonly_pubkey_hex_taker"); - let musig_pubkey_compressed_hex_maker: String = - row.get("musig_pubkey_compressed_hex_maker"); - let musig_pubkey_compressed_hex_taker: String = - row.get("musig_pubkey_compressed_hex_taker"); + // let taproot_xonly_pubkey_hex_maker: String = row.get("taproot_xonly_pubkey_hex_maker"); + // let taproot_xonly_pubkey_hex_taker: String = row.get("taproot_xonly_pubkey_hex_taker"); + // let musig_pubkey_compressed_hex_maker: String = + // row.get("musig_pubkey_compressed_hex_maker"); + // let musig_pubkey_compressed_hex_taker: String = + // row.get("musig_pubkey_compressed_hex_taker"); - Ok(EscrowPsbtConstructionData { - taproot_xonly_pubkey_hex_maker, - taproot_xonly_pubkey_hex_taker, - musig_pubkey_compressed_hex_maker, - musig_pubkey_compressed_hex_taker, - }) - } + // Ok(EscrowPsbtConstructionData { + // taproot_xonly_pubkey_hex_maker, + // taproot_xonly_pubkey_hex_taker, + // musig_pubkey_compressed_hex_maker, + // musig_pubkey_compressed_hex_taker, + // }) + // } pub async fn get_escrow_tx_amounts( &self, @@ -743,4 +745,26 @@ impl CoordinatorDB { escrow_fee_per_participant, )) } + + pub async fn fetch_maker_escrow_psbt_data( + &self, + trade_id: &str, + ) -> Result { + let row = sqlx::query( + "SELECT escrow_inputs_hex_maker_csv, change_address_maker, taproot_pubkey_hex_maker, musig_pubkey_hex FROM active_maker_offers WHERE offer_id = ?", + ) + .bind(trade_id) + .fetch_one(&*self.db_pool) + .await?; + + let deserialized_inputs = csv_hex_to_bdk_input(row.get("escrow_inputs_hex_maker_csv"))?; + let change_address: String = row.get("change_address_maker"); + + Ok(EscrowPsbtConstructionData { + escrow_input_utxos: deserialized_inputs, + change_address: Address::from_str(&change_address)?.assume_checked(), + taproot_xonly_pubkey_hex: row.get("taproot_pubkey_hex_maker"), + musig_pubkey_compressed_hex: row.get("musig_pubkey_hex"), + }) + } } diff --git a/taptrade-cli-demo/coordinator/src/main.rs b/taptrade-cli-demo/coordinator/src/main.rs index 351d554..4f6e5bc 100755 --- a/taptrade-cli-demo/coordinator/src/main.rs +++ b/taptrade-cli-demo/coordinator/src/main.rs @@ -21,7 +21,7 @@ use std::{ }; use tokio::sync::Mutex; use validator::{Validate, ValidationError}; -use wallet::{escrow_psbt::*, *}; +use wallet::{escrow_psbt::*, wallet_utils::*, *}; pub struct Coordinator { pub coordinator_db: Arc, diff --git a/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs b/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs index 079cb4d..065d142 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs @@ -1,5 +1,6 @@ use super::*; use bdk::{ + bitcoin::psbt::Input, descriptor::Descriptor, miniscript::{descriptor::TapTree, policy::Concrete, Tap}, }; @@ -7,11 +8,28 @@ use musig2::{secp256k1::PublicKey as MuSig2PubKey, KeyAggContext}; #[derive(Debug)] pub struct EscrowPsbtConstructionData { - pub taproot_xonly_pubkey_hex_maker: String, - pub taproot_xonly_pubkey_hex_taker: String, + pub taproot_xonly_pubkey_hex: String, + pub escrow_input_utxos: Vec, + pub change_address: Address, + // pub taproot_xonly_pubkey_hex_taker: String, // pub taproot_pubkey_hex_coordinator: String, - pub musig_pubkey_compressed_hex_maker: String, - pub musig_pubkey_compressed_hex_taker: String, + pub musig_pubkey_compressed_hex: String, + // pub musig_pubkey_compressed_hex_taker: String, +} + +impl EscrowPsbtConstructionData { + pub fn input_sum(&self) -> Result { + let mut input_sum = 0; + for input in &self.escrow_input_utxos { + if let Some(txout) = input.psbt_input.witness_utxo.as_ref() { + input_sum += txout.value; + } + } + if input_sum == 0 { + return Err(anyhow!("Input sum of escrow creation psbt input is 0")); + } + Ok(input_sum) + } } fn aggregate_musig_pubkeys(maker_musig_pubkey: &str, taker_musig_pubkey: &str) -> Result { @@ -31,12 +49,12 @@ fn aggregate_musig_pubkeys(maker_musig_pubkey: &str, taker_musig_pubkey: &str) - } pub fn build_escrow_transaction_output_descriptor( - escrow_data: &EscrowPsbtConstructionData, + maker_escrow_data: &EscrowPsbtConstructionData, + taker_escrow_data: &EscrowPsbtConstructionData, coordinator_pk: &XOnlyPublicKey, ) -> Result { - let taproot_pubkey_hex_maker = escrow_data.taproot_xonly_pubkey_hex_maker.clone(); - let maker_pk = taproot_pubkey_hex_maker; - let taker_pk = escrow_data.taproot_xonly_pubkey_hex_taker.clone(); + let maker_pk = maker_escrow_data.taproot_xonly_pubkey_hex.clone(); + let taker_pk = taker_escrow_data.taproot_xonly_pubkey_hex.clone(); let coordinator_pk = hex::encode(coordinator_pk.serialize()); // let script_a = format!("and(and(after({}),{}),{})", "144", maker_pk, coordinator_pk); @@ -84,8 +102,8 @@ pub fn build_escrow_transaction_output_descriptor( // An internal key, that defines the way to spend the transaction directly, using Key Path Spending let internal_agg_musig_key = aggregate_musig_pubkeys( - &escrow_data.musig_pubkey_compressed_hex_maker, - &escrow_data.musig_pubkey_compressed_hex_taker, + &maker_escrow_data.musig_pubkey_compressed_hex, + &taker_escrow_data.musig_pubkey_compressed_hex, )?; // Create the descriptor @@ -97,11 +115,11 @@ pub fn build_escrow_transaction_output_descriptor( Ok(descriptor.to_string()) } -pub fn assemble_escrow_psbts( - coordinator: &Coordinator, - escrow_data: &EscrowPsbtConstructionData, - coordinator_pk: &XOnlyPublicKey, -) -> Result<()> { - panic!("Implement wallet.build_escrow_psbt()"); - Ok(()) -} +// pub fn assemble_escrow_psbts( +// coordinator: &Coordinator, +// escrow_data: &EscrowPsbtConstructionData, +// coordinator_pk: &XOnlyPublicKey, +// ) -> Result<()> { +// panic!("Implement wallet.build_escrow_psbt()"); +// Ok(()) +// } diff --git a/taptrade-cli-demo/coordinator/src/wallet/mod.rs b/taptrade-cli-demo/coordinator/src/wallet/mod.rs index 47ca8f4..2c199ff 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/mod.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/mod.rs @@ -1,5 +1,5 @@ pub mod escrow_psbt; -mod utils; +pub mod wallet_utils; // pub mod verify_tx; #[cfg(test)] mod wallet_tests; @@ -14,21 +14,22 @@ use bdk::{ bip32::ExtendedPrivKey, consensus::encode::deserialize, key::{secp256k1, XOnlyPublicKey}, + taproot::TapLeaf, + Address, Network::Regtest, Transaction, }, bitcoincore_rpc::{Client, RawTx, RpcApi}, blockchain::{rpc::Auth, Blockchain, ConfigurableBlockchain, RpcBlockchain, RpcConfig}, + database::MemoryDatabase, sled::{self, Tree}, template::Bip86, wallet::verify::*, KeychainKind, SyncOptions, Wallet, }; use coordinator::mempool_monitoring::MempoolHandler; -use core::panic; use std::{collections::HashMap, str::FromStr}; use std::{fmt, ops::Deref}; -use utils::*; // use verify_tx::*; #[derive(Clone)] @@ -42,6 +43,7 @@ pub struct CoordinatorWallet { #[derive(Debug)] pub struct EscrowPsbt { + pub escrow_psbt_hex: String, pub escrow_output_descriptor: String, pub escrow_tx_fee_address: String, pub coordinator_xonly_escrow_pk: String, @@ -237,25 +239,92 @@ impl CoordinatorWallet { Ok(()) } - pub async fn get_escrow_psbt( + pub async fn create_escrow_psbt( &self, db: &Arc, taker_psbt_request: &OfferPsbtRequest, ) -> Result { - let trade_id = &taker_psbt_request.offer.offer_id_hex; - panic!("adjust"); - let escrow_pubkeys = db.fetch_escrow_tx_payout_data(trade_id).await?; + 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(&escrow_pubkeys, &coordinator_escrow_pk)?; - let escrow_tx_fee_address = self.get_new_address().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, - escrow_tx_fee_address, + escrow_tx_fee_address: escrow_coordinator_fee_address.to_string(), coordinator_xonly_escrow_pk: coordinator_escrow_pk.to_string(), escrow_amount_maker_sat, escrow_amount_taker_sat, diff --git a/taptrade-cli-demo/coordinator/src/wallet/utils.rs b/taptrade-cli-demo/coordinator/src/wallet/wallet_utils.rs similarity index 72% rename from taptrade-cli-demo/coordinator/src/wallet/utils.rs rename to taptrade-cli-demo/coordinator/src/wallet/wallet_utils.rs index 45961eb..d7b0adf 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/utils.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/wallet_utils.rs @@ -1,9 +1,16 @@ use super::*; use bdk::{ - bitcoin::{Address, Network}, + bitcoin::{psbt::Input, Address, Network}, blockchain::GetTx, database::Database, }; +use serde::Deserialize; + +#[derive(Deserialize, Debug)] +pub struct PsbtInput { + pub psbt_input: Input, + pub utxo: bdk::bitcoin::OutPoint, +} pub trait BondTx { fn input_sum(&self, blockchain: &B, db: &D) -> Result; @@ -56,3 +63,16 @@ impl BondTx for Transaction { self.output.iter().map(|output| output.value).sum() } } + +pub fn csv_hex_to_bdk_input(inputs_csv_hex: &str) -> Result> { + let mut inputs: Vec = Vec::new(); + for input_hex in inputs_csv_hex.split(',') { + let binary = hex::decode(input_hex)?; + let input: PsbtInput = bincode::deserialize(&binary)?; + inputs.push(input); + } + if inputs.is_empty() { + return Err(anyhow!("No inputs found in csv input value")); + } + Ok(inputs) +} diff --git a/taptrade-cli-demo/trader/src/communication/api.rs b/taptrade-cli-demo/trader/src/communication/api.rs index 7c89ce6..ee6d3c9 100644 --- a/taptrade-cli-demo/trader/src/communication/api.rs +++ b/taptrade-cli-demo/trader/src/communication/api.rs @@ -48,6 +48,7 @@ pub struct OfferTakenRequest { #[derive(Debug, Deserialize)] pub struct OfferTakenResponse { + pub escrow_psbt_hex: String, pub escrow_output_descriptor: String, pub escrow_tx_fee_address: String, pub escrow_amount_maker_sat: u64, diff --git a/taptrade-cli-demo/trader/src/communication/mod.rs b/taptrade-cli-demo/trader/src/communication/mod.rs index 37ac233..4e7cc27 100644 --- a/taptrade-cli-demo/trader/src/communication/mod.rs +++ b/taptrade-cli-demo/trader/src/communication/mod.rs @@ -66,51 +66,51 @@ impl BondRequirementResponse { } impl BondSubmissionRequest { - pub fn prepare_bond_request( - bond: &PartiallySignedTransaction, - payout_address: &AddressInfo, - musig_data: &mut MuSigData, - trader_config: &TraderSettings, - taproot_pubkey: &XOnlyPublicKey, - ) -> Result { - let signed_bond_hex = serialize_hex(&bond.to_owned().extract_tx()); - let musig_pub_nonce_hex = hex::encode(musig_data.nonce.get_pub_for_sharing()?.serialize()); - let musig_pubkey_hex = hex::encode(musig_data.public_key.to_string()); - let taproot_pubkey_hex = hex::encode(taproot_pubkey.serialize()); + // pub fn prepare_bond_request( + // bond: &partiallysignedtransaction, + // payout_address: &addressinfo, + // musig_data: &mut musigdata, + // trader_config: &tradersettings, + // taproot_pubkey: &xonlypublickey, + // ) -> result { + // let signed_bond_hex = serialize_hex(&bond.to_owned().extract_tx()); + // let musig_pub_nonce_hex = hex::encode(musig_data.nonce.get_pub_for_sharing()?.serialize()); + // let musig_pubkey_hex = hex::encode(musig_data.public_key.to_string()); + // let taproot_pubkey_hex = hex::encode(taproot_pubkey.serialize()); - let request = BondSubmissionRequest { - robohash_hex: trader_config.robosats_robohash_hex.clone(), - signed_bond_hex, - payout_address: payout_address.address.to_string(), - musig_pub_nonce_hex, - musig_pubkey_hex, - taproot_pubkey_hex, - }; - Ok(request) - } + // let request = bondsubmissionrequest { + // robohash_hex: trader_config.robosats_robohash_hex.clone(), + // signed_bond_hex, + // payout_address: payout_address.address.to_string(), + // musig_pub_nonce_hex, + // musig_pubkey_hex, + // taproot_pubkey_hex, + // }; + // ok(request) + // } pub fn send_maker( - robohash_hex: &str, - bond: &PartiallySignedTransaction, - musig_data: &mut MuSigData, - payout_address: &AddressInfo, + &self, // robohash_hex: &str, + // bond: &PartiallySignedTransaction, + // musig_data: &mut MuSigData, + // payout_address: &AddressInfo, trader_setup: &TraderSettings, - taproot_pubkey: &XOnlyPublicKey, + // taproot_pubkey: &XOnlyPublicKey, ) -> Result { - let request = Self::prepare_bond_request( - bond, - payout_address, - musig_data, - trader_setup, - taproot_pubkey, - )?; + // let request = Self::prepare_bond_request( + // bond, + // payout_address, + // musig_data, + // trader_setup, + // taproot_pubkey, + // )?; let client = reqwest::blocking::Client::new(); let res = client .post(format!( "{}{}", trader_setup.coordinator_endpoint, "/submit-maker-bond" )) - .json(&request) + .json(self) .send(); match res { Ok(res) => { diff --git a/taptrade-cli-demo/trader/src/trading/maker_utils.rs b/taptrade-cli-demo/trader/src/trading/maker_utils.rs index 7253eaf..465c4f5 100644 --- a/taptrade-cli-demo/trader/src/trading/maker_utils.rs +++ b/taptrade-cli-demo/trader/src/trading/maker_utils.rs @@ -12,22 +12,28 @@ impl ActiveOffer { trading_wallet.trade_onchain_assembly(&offer_conditions, maker_config)?; let (psbt_inputs_hex_csv, escrow_change_address) = - trading_wallet.get_escrow_psbt_inputs()?; + trading_wallet.get_escrow_psbt_inputs(offer_conditions.locking_amount_sat as i64)?; - let submission_result = BondSubmissionRequest::send_maker( - &maker_config.robosats_robohash_hex, - &bond, - &mut musig_data, - &payout_address, - maker_config, - &trading_wallet.taproot_pubkey, - )?; + let bond_submission_request = BondSubmissionRequest { + robohash_hex: maker_config.robosats_robohash_hex.clone(), + signed_bond_hex: bond.to_string(), + payout_address: payout_address.address.to_string(), + musig_pub_nonce_hex: hex::encode(musig_data.nonce.get_pub_for_sharing()?.serialize()), + musig_pubkey_hex: hex::encode(musig_data.public_key.to_string()), + taproot_pubkey_hex: hex::encode(&trading_wallet.taproot_pubkey.serialize()), + bdk_psbt_inputs_hex_csv: psbt_inputs_hex_csv, + client_change_address: escrow_change_address, + }; + + let submission_result = bond_submission_request.send_maker(maker_config)?; Ok(ActiveOffer { offer_id_hex: submission_result.offer_id_hex, used_musig_config: musig_data, used_bond: bond, expected_payout_address: payout_address, escrow_psbt: None, + psbt_inputs_hex_csv, + escrow_change_address, }) } diff --git a/taptrade-cli-demo/trader/src/trading/mod.rs b/taptrade-cli-demo/trader/src/trading/mod.rs index 2f9af23..0553c98 100644 --- a/taptrade-cli-demo/trader/src/trading/mod.rs +++ b/taptrade-cli-demo/trader/src/trading/mod.rs @@ -5,7 +5,7 @@ pub mod utils; use self::utils::ActiveOffer; use super::*; use crate::{ - cli::TraderSettings, + cli::{OfferType, TraderSettings}, communication::api::{ BondRequirementResponse, BondSubmissionRequest, IsOfferReadyRequest, OfferTakenRequest, OfferTakenResponse, PsbtSubmissionRequest, PublicOffer, PublicOffers, @@ -31,9 +31,9 @@ pub fn run_maker(maker_config: &TraderSettings) -> Result<()> { info!("Maker offer created: {:#?}", &offer); let escrow_psbt_requirements = offer.wait_until_taken(maker_config)?; - let escrow_psbt = wallet.get_escrow_psbt(escrow_psbt_requirements, maker_config)?; - // .validate_maker_psbt(&escrow_contract_psbt)? - // .sign_escrow_psbt(&mut escrow_contract_psbt)?; + let escrow_psbt = wallet + .validate_maker_psbt(&escrow_contract_psbt)? + .sign_escrow_psbt(&mut escrow_contract_psbt)?; // submit signed escrow psbt back to coordinator PsbtSubmissionRequest::submit_escrow_psbt( diff --git a/taptrade-cli-demo/trader/src/trading/utils.rs b/taptrade-cli-demo/trader/src/trading/utils.rs index ad92efc..b953d19 100644 --- a/taptrade-cli-demo/trader/src/trading/utils.rs +++ b/taptrade-cli-demo/trader/src/trading/utils.rs @@ -7,6 +7,8 @@ pub struct ActiveOffer { pub used_bond: PartiallySignedTransaction, pub expected_payout_address: AddressInfo, pub escrow_psbt: Option, + pub escrow_change_address: String, + pub psbt_inputs_hex_csv: String, } impl ActiveOffer { diff --git a/taptrade-cli-demo/trader/src/wallet/mod.rs b/taptrade-cli-demo/trader/src/wallet/mod.rs index 393583f..9e5610d 100644 --- a/taptrade-cli-demo/trader/src/wallet/mod.rs +++ b/taptrade-cli-demo/trader/src/wallet/mod.rs @@ -12,6 +12,7 @@ use bdk::{ bitcoin::{ self, bip32::ExtendedPrivKey, + consensus::encode::serialize_hex, key::{KeyPair, Secp256k1, XOnlyPublicKey}, psbt::{serialize, Input, PartiallySignedTransaction}, Address, Network, @@ -38,6 +39,12 @@ pub struct TradingWallet { pub taproot_pubkey: XOnlyPublicKey, } +#[derive(Serialize)] +pub struct PsbtInput { + pub psbt_input: Input, + pub utxo: bdk::bitcoin::OutPoint, +} + pub fn get_wallet_xprv(xprv_input: Option) -> Result { let xprv: ExtendedPrivKey; let network: Network = Network::Regtest; @@ -138,8 +145,12 @@ impl TradingWallet { // could use more advanced coin selection if neccessary for utxo in available_utxos { - let psbt_input = self.wallet.get_psbt_input(utxo, None, false)?; - inputs.push(hex::encode(bincode::serialize(&psbt_input)?)); + let psbt_input: Input = self.wallet.get_psbt_input(utxo, None, false)?; + let input = PsbtInput { + psbt_input, + utxo: utxo.outpoint, + }; + inputs.push(hex::encode(bincode::serialize(&input)?)); amount_sat -= utxo.txout.value as i64; if amount_sat <= 0 { break;