mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-07-21 10:13:23 +00:00
add keyspend context struct
This commit is contained in:
@ -106,7 +106,7 @@ pub struct TradeObligationsUnsatisfied {
|
|||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct PayoutSignatureRequest {
|
pub struct PayoutSignatureRequest {
|
||||||
pub partitial_sig_hex: String,
|
pub partial_sig_hex: String,
|
||||||
pub offer_id_hex: String,
|
pub offer_id_hex: String,
|
||||||
pub robohash_hex: String,
|
pub robohash_hex: String,
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ async fn request_offer_status_maker(
|
|||||||
/// receives the signed escrow psbt and verifies it
|
/// receives the signed escrow psbt and verifies it
|
||||||
/// Supposed to be the endpoint that both maker & taker will send their part of the PSBT to (with signatures), the
|
/// Supposed to be the endpoint that both maker & taker will send their part of the PSBT to (with signatures), the
|
||||||
/// coordinator then has to check if their signatures are valid and everything else is according to the agreed upon contract.
|
/// coordinator then has to check if their signatures are valid and everything else is according to the agreed upon contract.
|
||||||
/// Once the coordinator has received both partitial signed PSBTs he can assemble them together to a transaction and publish it to the bitcoin network.
|
/// Once the coordinator has received both partial signed PSBTs he can assemble them together to a transaction and publish it to the bitcoin network.
|
||||||
async fn submit_escrow_psbt(
|
async fn submit_escrow_psbt(
|
||||||
Extension(coordinator): Extension<Arc<Coordinator>>,
|
Extension(coordinator): Extension<Arc<Coordinator>>,
|
||||||
Json(payload): Json<PsbtSubmissionRequest>,
|
Json(payload): Json<PsbtSubmissionRequest>,
|
||||||
|
@ -332,17 +332,17 @@ pub async fn handle_payout_signature(
|
|||||||
|
|
||||||
check_offer_and_confirmation(&payload.offer_id_hex, &payload.robohash_hex, database).await?;
|
check_offer_and_confirmation(&payload.offer_id_hex, &payload.robohash_hex, database).await?;
|
||||||
|
|
||||||
let (maker_partitial_sig_hex, taker_partitial_sig_hex, payout_psbt_hex) = match database
|
let (maker_partial_sig_hex, taker_partial_sig_hex, payout_psbt_hex) = match database
|
||||||
.insert_partitial_sig_and_fetch_if_both(
|
.insert_partial_sig_and_fetch_if_both(
|
||||||
&payload.partitial_sig_hex,
|
&payload.partial_sig_hex,
|
||||||
&payload.offer_id_hex,
|
&payload.offer_id_hex,
|
||||||
&payload.robohash_hex,
|
&payload.robohash_hex,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(Some((maker_partitial_sig, taker_partitial_sig, payout_transaction_psbt_hex))) => (
|
Ok(Some((maker_partial_sig, taker_partial_sig, payout_transaction_psbt_hex))) => (
|
||||||
maker_partitial_sig,
|
maker_partial_sig,
|
||||||
taker_partitial_sig,
|
taker_partial_sig,
|
||||||
bdk::bitcoin::psbt::PartiallySignedTransaction::deserialize(
|
bdk::bitcoin::psbt::PartiallySignedTransaction::deserialize(
|
||||||
&hex::decode(payout_transaction_psbt_hex)
|
&hex::decode(payout_transaction_psbt_hex)
|
||||||
.map_err(|e| RequestError::CoordinatorError(e.to_string()))?,
|
.map_err(|e| RequestError::CoordinatorError(e.to_string()))?,
|
||||||
@ -352,8 +352,13 @@ pub async fn handle_payout_signature(
|
|||||||
Err(e) => return Err(RequestError::Database(e.to_string())),
|
Err(e) => return Err(RequestError::Database(e.to_string())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let aggregated_signature = wallet
|
warn!("Use musig2 validate partial sig to validate sigs before using to blame users providing wrong sigs");
|
||||||
.aggregate_partitial_signatures(&maker_partitial_sig_hex, &taker_partitial_sig_hex)?;
|
|
||||||
|
let aggregated_signature = wallet::payout_tx::aggregate_partial_signatures(
|
||||||
|
&maker_partial_sig_hex,
|
||||||
|
&taker_partial_sig_hex,
|
||||||
|
)
|
||||||
|
.map_err(|e| RequestError::CoordinatorError(e.to_string()))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -137,8 +137,8 @@ impl CoordinatorDB {
|
|||||||
musig_pubkey_compressed_hex_maker TEXT NOT NULL,
|
musig_pubkey_compressed_hex_maker TEXT NOT NULL,
|
||||||
musig_pub_nonce_hex_taker TEXT NOT NULL,
|
musig_pub_nonce_hex_taker TEXT NOT NULL,
|
||||||
musig_pubkey_compressed_hex_taker TEXT NOT NULL,
|
musig_pubkey_compressed_hex_taker TEXT NOT NULL,
|
||||||
musig_partitial_sig_hex_maker TEXT,
|
musig_partial_sig_hex_maker TEXT,
|
||||||
musig_partitial_sig_hex_taker TEXT,
|
musig_partial_sig_hex_taker TEXT,
|
||||||
escrow_psbt_hex TEXT NOT NULL,
|
escrow_psbt_hex TEXT NOT NULL,
|
||||||
escrow_psbt_txid TEXT NOT NULL,
|
escrow_psbt_txid TEXT NOT NULL,
|
||||||
signed_escrow_psbt_hex_maker TEXT,
|
signed_escrow_psbt_hex_maker TEXT,
|
||||||
@ -907,9 +907,9 @@ impl CoordinatorDB {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn insert_partitial_sig_and_fetch_if_both(
|
pub async fn insert_partial_sig_and_fetch_if_both(
|
||||||
&self,
|
&self,
|
||||||
partitial_sig_hex: &str,
|
partial_sig_hex: &str,
|
||||||
offer_id_hex: &str,
|
offer_id_hex: &str,
|
||||||
robohash_hex: &str,
|
robohash_hex: &str,
|
||||||
) -> Result<Option<(String, String, String)>> {
|
) -> Result<Option<(String, String, String)>> {
|
||||||
@ -921,24 +921,24 @@ impl CoordinatorDB {
|
|||||||
let is_already_there = match is_maker {
|
let is_already_there = match is_maker {
|
||||||
true => {
|
true => {
|
||||||
let status = sqlx::query(
|
let status = sqlx::query(
|
||||||
"SELECT musig_partitial_sig_maker FROM taken_offers WHERE offer_id = ?",
|
"SELECT musig_partial_sig_maker FROM taken_offers WHERE offer_id = ?",
|
||||||
)
|
)
|
||||||
.bind(offer_id_hex)
|
.bind(offer_id_hex)
|
||||||
.fetch_one(&*self.db_pool)
|
.fetch_one(&*self.db_pool)
|
||||||
.await?;
|
.await?;
|
||||||
status
|
status
|
||||||
.get::<Option<String>, _>("musig_partitial_sig_maker")
|
.get::<Option<String>, _>("musig_partial_sig_maker")
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
let status = sqlx::query(
|
let status = sqlx::query(
|
||||||
"SELECT musig_partitial_sig_taker FROM taken_offers WHERE offer_id = ?",
|
"SELECT musig_partial_sig_taker FROM taken_offers WHERE offer_id = ?",
|
||||||
)
|
)
|
||||||
.bind(offer_id_hex)
|
.bind(offer_id_hex)
|
||||||
.fetch_one(&*self.db_pool)
|
.fetch_one(&*self.db_pool)
|
||||||
.await?;
|
.await?;
|
||||||
status
|
status
|
||||||
.get::<Option<String>, _>("musig_partitial_sig_taker")
|
.get::<Option<String>, _>("musig_partial_sig_taker")
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -947,23 +947,23 @@ impl CoordinatorDB {
|
|||||||
return Err(anyhow!("Partial sig already submitted"));
|
return Err(anyhow!("Partial sig already submitted"));
|
||||||
} else {
|
} else {
|
||||||
let query = if is_maker {
|
let query = if is_maker {
|
||||||
"UPDATE taken_offers SET musig_partitial_sig_maker = ? WHERE offer_id = ?"
|
"UPDATE taken_offers SET musig_partial_sig_maker = ? WHERE offer_id = ?"
|
||||||
} else {
|
} else {
|
||||||
"UPDATE taken_offers SET musig_partitial_sig_taker = ? WHERE offer_id = ?"
|
"UPDATE taken_offers SET musig_partial_sig_taker = ? WHERE offer_id = ?"
|
||||||
};
|
};
|
||||||
sqlx::query(query)
|
sqlx::query(query)
|
||||||
.bind(partitial_sig_hex)
|
.bind(partial_sig_hex)
|
||||||
.bind(offer_id_hex)
|
.bind(offer_id_hex)
|
||||||
.execute(&*self.db_pool)
|
.execute(&*self.db_pool)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let row = sqlx::query(
|
let row = sqlx::query(
|
||||||
"SELECT musig_partitial_sig_maker, musig_partitial_sig_taker, payout_transaction_psbt_hex FROM taken_offers WHERE offer_id = ?",
|
"SELECT musig_partial_sig_maker, musig_partial_sig_taker, payout_transaction_psbt_hex FROM taken_offers WHERE offer_id = ?",
|
||||||
).bind(offer_id_hex).fetch_one(&*self.db_pool).await?;
|
).bind(offer_id_hex).fetch_one(&*self.db_pool).await?;
|
||||||
|
|
||||||
let maker_sig: Option<String> = row.try_get("musig_partitial_sig_maker")?;
|
let maker_sig: Option<String> = row.try_get("musig_partial_sig_maker")?;
|
||||||
let taker_sig: Option<String> = row.try_get("musig_partitial_sig_taker")?;
|
let taker_sig: Option<String> = row.try_get("musig_partial_sig_taker")?;
|
||||||
let payout_tx_hex: String = row.try_get("payout_transaction_psbt_hex")?;
|
let payout_tx_hex: String = row.try_get("payout_transaction_psbt_hex")?;
|
||||||
if let (Some(maker), Some(taker)) = (maker_sig, taker_sig) {
|
if let (Some(maker), Some(taker)) = (maker_sig, taker_sig) {
|
||||||
Ok(Some((maker, taker, payout_tx_hex)))
|
Ok(Some((maker, taker, payout_tx_hex)))
|
||||||
|
@ -4,6 +4,15 @@ use bdk::bitcoin::psbt::Input;
|
|||||||
use bdk::bitcoin::psbt::PartiallySignedTransaction;
|
use bdk::bitcoin::psbt::PartiallySignedTransaction;
|
||||||
use bdk::bitcoin::OutPoint;
|
use bdk::bitcoin::OutPoint;
|
||||||
use bdk::miniscript::Descriptor;
|
use bdk::miniscript::Descriptor;
|
||||||
|
use musig2::{AggNonce, KeyAggContext, PartialSignature};
|
||||||
|
|
||||||
|
pub struct KeyspendContext {
|
||||||
|
pub partial_maker_sig: PartialSignature,
|
||||||
|
pub partial_taker_sig: PartialSignature,
|
||||||
|
pub agg_nonce: AggNonce,
|
||||||
|
pub key_agg_context: KeyAggContext,
|
||||||
|
pub keyspend_psbt: PartiallySignedTransaction,
|
||||||
|
}
|
||||||
|
|
||||||
fn get_tx_fees_abs_sat(blockchain_backend: &RpcBlockchain) -> Result<(u64, u64)> {
|
fn get_tx_fees_abs_sat(blockchain_backend: &RpcBlockchain) -> Result<(u64, u64)> {
|
||||||
let feerate = blockchain_backend.estimate_fee(6)?;
|
let feerate = blockchain_backend.estimate_fee(6)?;
|
||||||
@ -14,9 +23,12 @@ fn get_tx_fees_abs_sat(blockchain_backend: &RpcBlockchain) -> Result<(u64, u64)>
|
|||||||
Ok((tx_fee_abs, tx_fee_abs / 2))
|
Ok((tx_fee_abs, tx_fee_abs / 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aggregate_partitial_signatures() -> anyhow::Result<String> {
|
// pub fn aggregate_partial_signatures(
|
||||||
Ok(())
|
// maker_sig_hex: &str,
|
||||||
}
|
// taker_sig_hex: &str,
|
||||||
|
// ) -> anyhow::Result<String> {
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
|
impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
|
||||||
fn get_escrow_utxo(
|
fn get_escrow_utxo(
|
||||||
|
@ -5,7 +5,7 @@ use super::*;
|
|||||||
use crate::{
|
use crate::{
|
||||||
cli::{OfferType, TraderSettings},
|
cli::{OfferType, TraderSettings},
|
||||||
trading::utils::ActiveOffer,
|
trading::utils::ActiveOffer,
|
||||||
wallet::{bond::Bond, musig2::MuSigData},
|
wallet::{bond::Bond, musig2_utils::MuSigData},
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use api::*;
|
use api::*;
|
||||||
|
@ -211,7 +211,7 @@ impl TradingWallet {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// creates a partitial signature to spend the keyspend path of the escrow output
|
/// creates a partial signature to spend the keyspend path of the escrow output
|
||||||
/// which will be returned to the coordinator for aggregation
|
/// which will be returned to the coordinator for aggregation
|
||||||
pub fn sign_keyspend_payout_psbt(
|
pub fn sign_keyspend_payout_psbt(
|
||||||
&self,
|
&self,
|
||||||
|
Reference in New Issue
Block a user