mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-09-11 11:34:06 +00:00
finish improvised psbt assembly coordinator side.
This commit is contained in:
10
taptrade-cli-demo/coordinator/Cargo.lock
generated
10
taptrade-cli-demo/coordinator/Cargo.lock
generated
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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<EscrowPsbtConstructionData> {
|
||||
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<EscrowPsbtConstructionData> {
|
||||
// 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<EscrowPsbtConstructionData> {
|
||||
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"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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<CoordinatorDB>,
|
||||
|
@ -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<PsbtInput>,
|
||||
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<u64> {
|
||||
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<String> {
|
||||
@ -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<String> {
|
||||
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(())
|
||||
// }
|
||||
|
@ -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<D: bdk::database::BatchDatabase> {
|
||||
|
||||
#[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<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_escrow_psbt(
|
||||
pub async fn create_escrow_psbt(
|
||||
&self,
|
||||
db: &Arc<CoordinatorDB>,
|
||||
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 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,
|
||||
|
@ -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<D: Database, B: GetTx>(&self, blockchain: &B, db: &D) -> Result<u64>;
|
||||
@ -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<Vec<PsbtInput>> {
|
||||
let mut inputs: Vec<PsbtInput> = 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)
|
||||
}
|
@ -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,
|
||||
|
@ -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<BondSubmissionRequest> {
|
||||
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<bondsubmissionrequest> {
|
||||
// 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<OrderActivatedResponse> {
|
||||
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) => {
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -7,6 +7,8 @@ pub struct ActiveOffer {
|
||||
pub used_bond: PartiallySignedTransaction,
|
||||
pub expected_payout_address: AddressInfo,
|
||||
pub escrow_psbt: Option<PartiallySignedTransaction>,
|
||||
pub escrow_change_address: String,
|
||||
pub psbt_inputs_hex_csv: String,
|
||||
}
|
||||
|
||||
impl ActiveOffer {
|
||||
|
@ -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<String>) -> Result<ExtendedPrivKey> {
|
||||
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;
|
||||
|
Reference in New Issue
Block a user