mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-07-19 09:13:39 +00:00
add client psbt input assembly/serialization
This commit is contained in:
@ -30,6 +30,8 @@ pub struct BondSubmissionRequest {
|
||||
pub taproot_pubkey_hex: String,
|
||||
pub musig_pub_nonce_hex: String,
|
||||
pub musig_pubkey_hex: String,
|
||||
pub bdk_psbt_inputs_hex_csv: String,
|
||||
pub client_change_address: String,
|
||||
}
|
||||
|
||||
// Response after step2 if offer creation was successful and the offer is now online in the orderbook
|
||||
|
@ -338,11 +338,7 @@ fn taker_unresponsive(
|
||||
|
||||
println!("here");
|
||||
|
||||
wallet.add_signer(
|
||||
KeychainKind::External,
|
||||
SignerOrdering(0),
|
||||
Arc::new(signer)
|
||||
);
|
||||
wallet.add_signer(KeychainKind::External, SignerOrdering(0), Arc::new(signer));
|
||||
|
||||
// // Step 3: Sign the transaction
|
||||
// let mut psbt = PartiallySignedTransaction::from_str("TODO: paste the PSBT obtained in step 3 here")?;
|
||||
@ -445,11 +441,7 @@ fn coordinator_sign(
|
||||
},
|
||||
);
|
||||
|
||||
wallet.add_signer(
|
||||
KeychainKind::External,
|
||||
SignerOrdering(0),
|
||||
Arc::new(signer)
|
||||
);
|
||||
wallet.add_signer(KeychainKind::External, SignerOrdering(0), Arc::new(signer));
|
||||
// Print the PSBT before signing
|
||||
println!("PSBT before signing: {:?}", psbt);
|
||||
for (i, input) in (0_u32..).zip(psbt.inputs.iter()) {
|
||||
@ -468,12 +460,11 @@ fn coordinator_sign(
|
||||
Ok(_) => {
|
||||
println!("Successfully signed PSBT.");
|
||||
println!("Final PSBT: {:?}", psbt);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error signing PSBT: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error creating wallet: {:?}", e);
|
||||
@ -487,7 +478,7 @@ fn coordinator_sign(
|
||||
mod tests {
|
||||
use crate::coordinator;
|
||||
|
||||
use super::*;
|
||||
use super::*;
|
||||
use anyhow::{Context, Error};
|
||||
// use bdk::blockchain::ElectrumBlockchain;
|
||||
// use bdk::sled;
|
||||
|
@ -133,10 +133,7 @@ pub async fn handle_taker_bond(
|
||||
}
|
||||
debug!("\nTaker bond validation successful");
|
||||
|
||||
let escrow_output_data = match wallet
|
||||
.get_escrow_psbt_outputs(database, &payload.offer.offer_id_hex)
|
||||
.await
|
||||
{
|
||||
let escrow_output_data = match wallet.get_escrow_psbt(database, &payload).await {
|
||||
Ok(escrow_output_data) => escrow_output_data,
|
||||
Err(e) => {
|
||||
return Err(BondError::CoordinatorError(e.to_string()));
|
||||
|
@ -100,6 +100,8 @@ impl CoordinatorDB {
|
||||
bond_amount_sat INTEGER NOT NULL,
|
||||
bond_tx_hex TEXT NOT NULL,
|
||||
payout_address TEXT NOT NULL,
|
||||
change_address_maker TEXT NOT NULL,
|
||||
escrow_inputs_hex_maker_csv TEXT NOT NULL,
|
||||
taproot_pubkey_hex_maker TEXT NOT NULL,
|
||||
musig_pub_nonce_hex TEXT NOT NULL,
|
||||
musig_pubkey_hex TEXT NOT NULL,
|
||||
@ -241,8 +243,9 @@ impl CoordinatorDB {
|
||||
);
|
||||
sqlx::query(
|
||||
"INSERT OR REPLACE INTO active_maker_offers (offer_id, robohash, is_buy_order, amount_sat,
|
||||
bond_ratio, offer_duration_ts, bond_address, bond_amount_sat, bond_tx_hex, payout_address, taproot_pubkey_hex_maker, musig_pub_nonce_hex, musig_pubkey_hex, taker_bond_address)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
bond_ratio, offer_duration_ts, bond_address, bond_amount_sat, bond_tx_hex, payout_address, taproot_pubkey_hex_maker, musig_pub_nonce_hex, musig_pubkey_hex, taker_bond_address,
|
||||
change_address_maker, escrow_inputs_hex_maker_csv)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
)
|
||||
.bind(offer_id)
|
||||
.bind(hex::decode(&data.robohash_hex)?)
|
||||
@ -258,6 +261,8 @@ impl CoordinatorDB {
|
||||
.bind(data.musig_pub_nonce_hex.clone())
|
||||
.bind(data.musig_pubkey_hex.clone())
|
||||
.bind(taker_bond_address)
|
||||
.bind(data.client_change_address.clone())
|
||||
.bind(data.bdk_psbt_inputs_hex_csv.clone())
|
||||
.execute(&*self.db_pool)
|
||||
.await?;
|
||||
|
||||
|
@ -25,6 +25,7 @@ use bdk::{
|
||||
KeychainKind, SyncOptions, Wallet,
|
||||
};
|
||||
use coordinator::mempool_monitoring::MempoolHandler;
|
||||
use core::panic;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
use std::{fmt, ops::Deref};
|
||||
use utils::*;
|
||||
@ -236,11 +237,13 @@ impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_escrow_psbt_outputs(
|
||||
pub async fn get_escrow_psbt(
|
||||
&self,
|
||||
db: &Arc<CoordinatorDB>,
|
||||
trade_id: &str,
|
||||
taker_psbt_request: &OfferPsbtRequest,
|
||||
) -> Result<EscrowPsbt> {
|
||||
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 coordinator_escrow_pk = self.get_coordinator_taproot_pk().await?;
|
||||
let escrow_output_descriptor =
|
||||
|
10
taptrade-cli-demo/trader/Cargo.lock
generated
10
taptrade-cli-demo/trader/Cargo.lock
generated
@ -175,6 +175,15 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445"
|
||||
|
||||
[[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"
|
||||
@ -1587,6 +1596,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bdk",
|
||||
"bincode",
|
||||
"dotenvy",
|
||||
"env_logger",
|
||||
"hex",
|
||||
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
bdk = "0.29.0"
|
||||
bincode = "1.3.3"
|
||||
dotenvy = "0.15.0"
|
||||
env_logger = "0.11.3"
|
||||
hex = "0.4.3"
|
||||
|
@ -29,6 +29,8 @@ pub struct BondSubmissionRequest {
|
||||
pub taproot_pubkey_hex: String,
|
||||
pub musig_pub_nonce_hex: String,
|
||||
pub musig_pubkey_hex: String,
|
||||
pub bdk_psbt_inputs_hex_csv: String,
|
||||
pub client_change_address: String,
|
||||
}
|
||||
|
||||
// Response after step2 if offer creation was successful and the offer is now online in the orderbook
|
||||
|
@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::{f32::consts::E, str::FromStr, thread::sleep, time::Duration};
|
||||
|
||||
impl BondRequirementResponse {
|
||||
fn _format_request(trader_setup: &TraderSettings) -> OrderRequest {
|
||||
fn _format_order_request(trader_setup: &TraderSettings) -> OrderRequest {
|
||||
let amount: u64;
|
||||
let is_buy_order = match &trader_setup.trade_type {
|
||||
OfferType::Buy(val) => {
|
||||
@ -46,7 +46,7 @@ impl BondRequirementResponse {
|
||||
let endpoint = format!("{}{}", trader_setup.coordinator_endpoint, "/create-offer");
|
||||
let res = match client
|
||||
.post(endpoint)
|
||||
.json(&Self::_format_request(trader_setup))
|
||||
.json(&Self::_format_order_request(trader_setup))
|
||||
.send()
|
||||
{
|
||||
Ok(res) => res,
|
||||
|
@ -10,6 +10,10 @@ impl ActiveOffer {
|
||||
debug!("Offer conditions fetched: {:#?}", &offer_conditions);
|
||||
let (bond, mut musig_data, payout_address) =
|
||||
trading_wallet.trade_onchain_assembly(&offer_conditions, maker_config)?;
|
||||
|
||||
let (psbt_inputs_hex_csv, escrow_change_address) =
|
||||
trading_wallet.get_escrow_psbt_inputs()?;
|
||||
|
||||
let submission_result = BondSubmissionRequest::send_maker(
|
||||
&maker_config.robosats_robohash_hex,
|
||||
&bond,
|
||||
|
@ -13,7 +13,7 @@ use bdk::{
|
||||
self,
|
||||
bip32::ExtendedPrivKey,
|
||||
key::{KeyPair, Secp256k1, XOnlyPublicKey},
|
||||
psbt::PartiallySignedTransaction,
|
||||
psbt::{serialize, Input, PartiallySignedTransaction},
|
||||
Address, Network,
|
||||
},
|
||||
blockchain::ElectrumBlockchain,
|
||||
@ -28,6 +28,7 @@ use bdk::{
|
||||
use bond::Bond;
|
||||
use cli::OfferType;
|
||||
use musig2::MuSigData;
|
||||
use serde::Serialize;
|
||||
use std::str::FromStr;
|
||||
use wallet_utils::get_seed;
|
||||
|
||||
@ -89,43 +90,69 @@ impl TradingWallet {
|
||||
Ok((bond, musig_data, payout_address))
|
||||
}
|
||||
|
||||
pub fn get_escrow_psbt(
|
||||
&self,
|
||||
escrow_psbt_requirements: OfferTakenResponse,
|
||||
trader_config: &TraderSettings,
|
||||
) -> Result<PartiallySignedTransaction> {
|
||||
let fee_output = Address::from_str(&escrow_psbt_requirements.escrow_tx_fee_address)?
|
||||
.assume_checked()
|
||||
.script_pubkey();
|
||||
let escrow_output = {
|
||||
let temp_wallet = Wallet::new(
|
||||
&escrow_psbt_requirements.escrow_output_descriptor,
|
||||
None,
|
||||
Network::Regtest,
|
||||
MemoryDatabase::new(),
|
||||
)?;
|
||||
temp_wallet.get_address(AddressIndex::New)?.script_pubkey()
|
||||
};
|
||||
self.wallet.sync(&self.backend, SyncOptions::default())?;
|
||||
// pub fn get_escrow_psbt(
|
||||
// &self,
|
||||
// escrow_psbt_requirements: OfferTakenResponse,
|
||||
// trader_config: &TraderSettings,
|
||||
// ) -> Result<PartiallySignedTransaction> {
|
||||
// let fee_output = Address::from_str(&escrow_psbt_requirements.escrow_tx_fee_address)?
|
||||
// .assume_checked()
|
||||
// .script_pubkey();
|
||||
// let escrow_output = {
|
||||
// let temp_wallet = Wallet::new(
|
||||
// &escrow_psbt_requirements.escrow_output_descriptor,
|
||||
// None,
|
||||
// Network::Regtest,
|
||||
// MemoryDatabase::new(),
|
||||
// )?;
|
||||
// temp_wallet.get_address(AddressIndex::New)?.script_pubkey()
|
||||
// };
|
||||
// self.wallet.sync(&self.backend, SyncOptions::default())?;
|
||||
|
||||
let escrow_amount_sat = match trader_config.trade_type {
|
||||
OfferType::Buy(_) => escrow_psbt_requirements.escrow_amount_taker_sat,
|
||||
OfferType::Sell(_) => escrow_psbt_requirements.escrow_amount_maker_sat,
|
||||
};
|
||||
let (mut psbt, details) = {
|
||||
let mut builder = self.wallet.build_tx();
|
||||
builder
|
||||
.add_recipient(escrow_output, escrow_amount_sat)
|
||||
.add_recipient(
|
||||
fee_output,
|
||||
escrow_psbt_requirements.escrow_fee_sat_per_participant,
|
||||
)
|
||||
.fee_rate(FeeRate::from_sat_per_vb(10.0));
|
||||
builder.finish()?
|
||||
};
|
||||
debug!("Signing escrow psbt.");
|
||||
self.wallet.sign(&mut psbt, SignOptions::default())?;
|
||||
Ok(psbt)
|
||||
// let escrow_amount_sat = match trader_config.trade_type {
|
||||
// OfferType::Buy(_) => escrow_psbt_requirements.escrow_amount_taker_sat,
|
||||
// OfferType::Sell(_) => escrow_psbt_requirements.escrow_amount_maker_sat,
|
||||
// };
|
||||
// let (mut psbt, details) = {
|
||||
// let mut builder = self.wallet.build_tx();
|
||||
// builder
|
||||
// .add_recipient(escrow_output, escrow_amount_sat)
|
||||
// .add_recipient(
|
||||
// fee_output,
|
||||
// escrow_psbt_requirements.escrow_fee_sat_per_participant,
|
||||
// )
|
||||
// .fee_rate(FeeRate::from_sat_per_vb(10.0));
|
||||
// builder.finish()?
|
||||
// };
|
||||
// debug!("Signing escrow psbt.");
|
||||
// self.wallet.sign(&mut psbt, SignOptions::default())?;
|
||||
// Ok(psbt)
|
||||
// }
|
||||
|
||||
/// returns suitable inputs (hex, csv serialized) and a change address for the assembly of the escrow psbt (coordinator side)
|
||||
pub fn get_escrow_psbt_inputs(&self, mut amount_sat: i64) -> Result<(String, String)> {
|
||||
let mut inputs: Vec<String> = Vec::new();
|
||||
|
||||
self.wallet.sync(&self.backend, SyncOptions::default())?;
|
||||
let available_utxos = self.wallet.list_unspent()?;
|
||||
|
||||
// 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)?));
|
||||
amount_sat -= utxo.txout.value as i64;
|
||||
if amount_sat <= 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let serialized_inputs = inputs.join(",");
|
||||
|
||||
let change_address = self
|
||||
.wallet
|
||||
.get_address(AddressIndex::New)?
|
||||
.address
|
||||
.to_string();
|
||||
Ok((serialized_inputs, change_address))
|
||||
}
|
||||
|
||||
// validate that the taker psbt references the correct inputs and amounts
|
||||
|
Reference in New Issue
Block a user