mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-08-06 10:00:00 +00:00
use map_err for coordinator mod error handling, add endpoints for partitial sig
This commit is contained in:
@ -103,3 +103,10 @@ pub struct TradeObligationsUnsatisfied {
|
||||
pub robohash_hex: String,
|
||||
pub offer_id_hex: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PayoutSignatureRequest {
|
||||
pub partitial_sig_hex: String,
|
||||
pub offer_id_hex: String,
|
||||
pub robohash_hex: String,
|
||||
}
|
||||
|
@ -260,6 +260,31 @@ async fn poll_final_payout(
|
||||
}
|
||||
}
|
||||
|
||||
async fn submit_payout_signature(
|
||||
Extension(coordinator): Extension<Arc<Coordinator>>,
|
||||
Json(payload): Json<PayoutSignatureRequest>,
|
||||
) -> Result<Response, AppError> {
|
||||
match handle_payout_signature(&payload, coordinator).await {
|
||||
Ok(_) => Ok(StatusCode::OK.into_response()),
|
||||
// Err(RequestError::NotConfirmed) => {
|
||||
// info!("Offer tx for final payout not confirmed");
|
||||
// Ok(StatusCode::NOT_ACCEPTABLE.into_response())
|
||||
// }
|
||||
// Err(RequestError::NotFound) => {
|
||||
// info!("Offer for final payout not found");
|
||||
// Ok(StatusCode::NOT_FOUND.into_response())
|
||||
// }
|
||||
// Err(RequestError::Database(e)) => {
|
||||
// error!("Database error fetching final payout: {e}");
|
||||
// Ok(StatusCode::INTERNAL_SERVER_ERROR.into_response())
|
||||
// }
|
||||
_ => {
|
||||
error!("Unknown error handling submit_payout_signature()");
|
||||
Ok(StatusCode::INTERNAL_SERVER_ERROR.into_response())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn test_api() -> &'static str {
|
||||
"Hello, World!"
|
||||
}
|
||||
@ -280,6 +305,7 @@ pub async fn api_server(coordinator: Arc<Coordinator>) -> Result<()> {
|
||||
)
|
||||
.route("/request-escrow", post(request_escrow))
|
||||
.route("/poll-final-payout", post(poll_final_payout))
|
||||
.route("/submit-payout-signature", post(submit_payout_signature))
|
||||
.layer(Extension(coordinator));
|
||||
// add other routes here
|
||||
|
||||
|
@ -37,51 +37,28 @@ pub async fn handle_maker_bond(
|
||||
let wallet = &coordinator.coordinator_wallet;
|
||||
let database = &coordinator.coordinator_db;
|
||||
|
||||
let bond_requirements = if let Ok(requirements) = database
|
||||
let bond_requirements = database
|
||||
.fetch_bond_requirements(&payload.robohash_hex)
|
||||
.await
|
||||
{
|
||||
requirements
|
||||
} else {
|
||||
return Err(BondError::BondNotFound);
|
||||
};
|
||||
.map_err(|_| BondError::BondNotFound)?;
|
||||
|
||||
match wallet
|
||||
wallet
|
||||
.validate_bond_tx_hex(&payload.signed_bond_hex, &bond_requirements)
|
||||
.await
|
||||
{
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
return Err(BondError::InvalidBond(e.to_string()));
|
||||
}
|
||||
}
|
||||
.map_err(|e| BondError::InvalidBond(e.to_string()))?;
|
||||
debug!("\nBond validation successful");
|
||||
let offer_id_hex: String = generate_random_order_id(16); // 16 bytes random offer id, maybe a different system makes more sense later on? (uuid or increasing counter...)
|
||||
// create address for taker bond
|
||||
let new_taker_bond_address = match wallet.get_new_address().await {
|
||||
Ok(address) => address,
|
||||
Err(e) => {
|
||||
let error = format!(
|
||||
"Error generating taker bond address for offer id: {}. Error: {e}",
|
||||
offer_id_hex
|
||||
);
|
||||
return Err(BondError::CoordinatorError(error.to_string()));
|
||||
}
|
||||
};
|
||||
// insert bond into sql database and move offer to different table
|
||||
let bond_locked_until_timestamp = match database
|
||||
let new_taker_bond_address = wallet
|
||||
.get_new_address()
|
||||
.await
|
||||
.map_err(|e| BondError::CoordinatorError(e.to_string()))?;
|
||||
|
||||
let bond_locked_until_timestamp = database
|
||||
.move_offer_to_active(payload, &offer_id_hex, new_taker_bond_address)
|
||||
.await
|
||||
{
|
||||
Ok(timestamp) => timestamp,
|
||||
Err(e) => {
|
||||
debug!(
|
||||
"Error in validate_bond_tx_hex in move_offer_to_active: {}",
|
||||
e
|
||||
);
|
||||
return Err(BondError::CoordinatorError(e.to_string()));
|
||||
}
|
||||
};
|
||||
.map_err(|e| BondError::CoordinatorError(e.to_string()))?;
|
||||
|
||||
Ok(OfferActivatedResponse {
|
||||
bond_locked_until_timestamp,
|
||||
offer_id_hex,
|
||||
@ -94,12 +71,11 @@ pub async fn get_public_offers(
|
||||
) -> Result<PublicOffers, FetchOffersError> {
|
||||
let database = &coordinator.coordinator_db;
|
||||
|
||||
let offers = match database.fetch_suitable_offers(request).await {
|
||||
Ok(offers) => offers,
|
||||
Err(e) => {
|
||||
return Err(FetchOffersError::Database(e.to_string()));
|
||||
}
|
||||
};
|
||||
let offers = database
|
||||
.fetch_suitable_offers(request)
|
||||
.await
|
||||
.map_err(|e| FetchOffersError::Database(e.to_string()))?;
|
||||
|
||||
if offers.is_none() {
|
||||
return Err(FetchOffersError::NoOffersAvailable);
|
||||
}
|
||||
@ -115,41 +91,30 @@ pub async fn handle_taker_bond(
|
||||
|
||||
let bond_requirements = database
|
||||
.fetch_taker_bond_requirements(&payload.offer.offer_id_hex)
|
||||
.await;
|
||||
.await
|
||||
.map_err(|_| BondError::BondNotFound)?;
|
||||
|
||||
wallet
|
||||
.validate_bond_tx_hex(&payload.trade_data.signed_bond_hex, &bond_requirements)
|
||||
.await
|
||||
.map_err(|e| BondError::InvalidBond(e.to_string()))?;
|
||||
|
||||
match bond_requirements {
|
||||
Ok(bond_requirements) => {
|
||||
match wallet
|
||||
.validate_bond_tx_hex(&payload.trade_data.signed_bond_hex, &bond_requirements)
|
||||
.await
|
||||
{
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
return Err(BondError::InvalidBond(e.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => return Err(BondError::BondNotFound),
|
||||
}
|
||||
debug!("\nTaker bond validation successful");
|
||||
|
||||
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()));
|
||||
}
|
||||
};
|
||||
let escrow_output_data = wallet
|
||||
.create_escrow_psbt(database, &payload)
|
||||
.await
|
||||
.map_err(|e| BondError::CoordinatorError(e.to_string()))?;
|
||||
debug!(
|
||||
"\nEscrow PSBT creation successful: {:?}",
|
||||
escrow_output_data
|
||||
);
|
||||
|
||||
if let Err(e) = database
|
||||
database
|
||||
.add_taker_info_and_move_table(payload, &escrow_output_data)
|
||||
.await
|
||||
{
|
||||
return Err(BondError::CoordinatorError(e.to_string()));
|
||||
}
|
||||
.map_err(|e| BondError::CoordinatorError(e.to_string()))?;
|
||||
|
||||
trace!("Taker information added to database and moved table successfully");
|
||||
Ok(OfferTakenResponse {
|
||||
escrow_psbt_hex: escrow_output_data.escrow_psbt_hex,
|
||||
@ -209,13 +174,10 @@ pub async fn fetch_escrow_confirmation_status(
|
||||
Err(e) => return Err(FetchEscrowConfirmationError::Database(e.to_string())),
|
||||
}
|
||||
|
||||
match database
|
||||
database
|
||||
.fetch_escrow_tx_confirmation_status(&payload.offer_id_hex)
|
||||
.await
|
||||
{
|
||||
Ok(status) => Ok(status),
|
||||
Err(e) => return Err(FetchEscrowConfirmationError::Database(e.to_string())),
|
||||
}
|
||||
.map_err(|e| FetchEscrowConfirmationError::Database(e.to_string()))
|
||||
}
|
||||
|
||||
pub async fn handle_signed_escrow_psbt(
|
||||
@ -234,13 +196,11 @@ pub async fn handle_signed_escrow_psbt(
|
||||
Err(e) => return Err(RequestError::Database(e.to_string())),
|
||||
};
|
||||
|
||||
match wallet
|
||||
wallet
|
||||
.validate_escrow_init_psbt(&payload.signed_psbt_hex)
|
||||
.await
|
||||
{
|
||||
Ok(()) => (),
|
||||
Err(e) => return Err(RequestError::PsbtInvalid(e.to_string())),
|
||||
};
|
||||
.map_err(|e| RequestError::PsbtInvalid(e.to_string()))?;
|
||||
|
||||
match database.insert_signed_escrow_psbt(payload).await {
|
||||
Ok(false) => return Err(RequestError::PsbtAlreadySubmitted),
|
||||
Ok(true) => (),
|
||||
@ -257,12 +217,10 @@ pub async fn handle_signed_escrow_psbt(
|
||||
Err(e) => return Err(RequestError::Database(e.to_string())),
|
||||
};
|
||||
|
||||
if let Err(e) = wallet
|
||||
wallet
|
||||
.combine_and_broadcast_escrow_psbt(&maker_psbt, &taker_psbt)
|
||||
.await
|
||||
{
|
||||
return Err(RequestError::PsbtInvalid(e.to_string()));
|
||||
}
|
||||
.map_err(|e| RequestError::PsbtInvalid(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -274,12 +232,10 @@ pub async fn handle_obligation_confirmation(
|
||||
let database = &coordinator.coordinator_db;
|
||||
|
||||
check_offer_and_confirmation(&payload.offer_id_hex, &payload.robohash_hex, database).await?;
|
||||
if let Err(e) = database
|
||||
database
|
||||
.set_trader_happy_field(&payload.offer_id_hex, &payload.robohash_hex, true)
|
||||
.await
|
||||
{
|
||||
return Err(RequestError::Database(e.to_string()));
|
||||
}
|
||||
.map_err(|e| RequestError::Database(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -290,13 +246,10 @@ pub async fn initiate_escrow(
|
||||
let database = &coordinator.coordinator_db;
|
||||
|
||||
check_offer_and_confirmation(&payload.offer_id_hex, &payload.robohash_hex, database).await?;
|
||||
|
||||
if let Err(e) = database
|
||||
database
|
||||
.set_trader_happy_field(&payload.offer_id_hex, &payload.robohash_hex, false)
|
||||
.await
|
||||
{
|
||||
return Err(RequestError::Database(e.to_string()));
|
||||
}
|
||||
.map_err(|e| RequestError::Database(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -307,29 +260,30 @@ pub async fn handle_final_payout(
|
||||
) -> Result<PayoutProcessingResult, RequestError> {
|
||||
let database = &coordinator.coordinator_db;
|
||||
|
||||
check_offer_and_confirmation(&payload.offer_id_hex, &payload.robohash_hex, database).await?;
|
||||
|
||||
let trader_happiness = match database.fetch_trader_happiness(&payload.offer_id_hex).await {
|
||||
Ok(happiness) => happiness,
|
||||
Err(e) => return Err(RequestError::Database(e.to_string())),
|
||||
};
|
||||
let trader_happiness = database
|
||||
.fetch_trader_happiness(&payload.offer_id_hex)
|
||||
.await
|
||||
.map_err(|e| RequestError::Database(e.to_string()))?;
|
||||
|
||||
if trader_happiness.maker_happy.is_some_and(|x| x)
|
||||
&& trader_happiness.taker_happy.is_some_and(|x| x)
|
||||
{
|
||||
let escrow_payout_data = match database.fetch_payout_data(&payload.offer_id_hex).await {
|
||||
Ok(payout_data) => payout_data,
|
||||
Err(e) => return Err(RequestError::Database(e.to_string())),
|
||||
};
|
||||
let escrow_payout_data = database
|
||||
.fetch_payout_data(&payload.offer_id_hex)
|
||||
.await
|
||||
.map_err(|e| RequestError::Database(e.to_string()))?;
|
||||
|
||||
let payout_keyspend_psbt_hex = match coordinator
|
||||
let payout_keyspend_psbt_hex = coordinator
|
||||
.coordinator_wallet
|
||||
.assemble_keyspend_payout_psbt(&escrow_payout_data)
|
||||
.await
|
||||
{
|
||||
Ok(psbt_hex) => psbt_hex,
|
||||
Err(e) => return Err(RequestError::CoordinatorError(e.to_string())),
|
||||
};
|
||||
.map_err(|e| RequestError::CoordinatorError(e.to_string()))?;
|
||||
|
||||
database
|
||||
.insert_keyspend_payout_psbt(&payload.offer_id_hex, &payout_keyspend_psbt_hex)
|
||||
.await
|
||||
.map_err(|e| RequestError::Database(e.to_string()))?;
|
||||
|
||||
return Ok(PayoutProcessingResult::ReadyPSBT(PayoutResponse {
|
||||
payout_psbt_hex: payout_keyspend_psbt_hex,
|
||||
agg_musig_nonce_hex: escrow_payout_data.agg_musig_nonce.to_string(),
|
||||
@ -368,3 +322,38 @@ pub async fn handle_final_payout(
|
||||
Ok(PayoutProcessingResult::DecidingEscrow)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_payout_signature(
|
||||
payload: &PayoutSignatureRequest,
|
||||
coordinator: Arc<Coordinator>,
|
||||
) -> Result<(), RequestError> {
|
||||
let database = &coordinator.coordinator_db;
|
||||
let wallet = &coordinator.coordinator_wallet;
|
||||
|
||||
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
|
||||
.insert_partitial_sig_and_fetch_if_both(
|
||||
&payload.partitial_sig_hex,
|
||||
&payload.offer_id_hex,
|
||||
&payload.robohash_hex,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(Some((maker_partitial_sig, taker_partitial_sig, payout_transaction_psbt_hex))) => (
|
||||
maker_partitial_sig,
|
||||
taker_partitial_sig,
|
||||
bdk::bitcoin::psbt::PartiallySignedTransaction::deserialize(
|
||||
&hex::decode(payout_transaction_psbt_hex)
|
||||
.map_err(|e| RequestError::CoordinatorError(e.to_string()))?,
|
||||
),
|
||||
),
|
||||
Ok(None) => return Ok(()),
|
||||
Err(e) => return Err(RequestError::Database(e.to_string())),
|
||||
};
|
||||
|
||||
let aggregated_signature = wallet
|
||||
.aggregate_partitial_signatures(&maker_partitial_sig_hex, &taker_partitial_sig_hex)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -137,6 +137,8 @@ impl CoordinatorDB {
|
||||
musig_pubkey_compressed_hex_maker TEXT NOT NULL,
|
||||
musig_pub_nonce_hex_taker TEXT NOT NULL,
|
||||
musig_pubkey_compressed_hex_taker TEXT NOT NULL,
|
||||
musig_partitial_sig_hex_maker TEXT,
|
||||
musig_partitial_sig_hex_taker TEXT,
|
||||
escrow_psbt_hex TEXT NOT NULL,
|
||||
escrow_psbt_txid TEXT NOT NULL,
|
||||
signed_escrow_psbt_hex_maker TEXT,
|
||||
@ -150,7 +152,8 @@ impl CoordinatorDB {
|
||||
escrow_amount_maker_sat INTEGER,
|
||||
escrow_amount_taker_sat INTEGER,
|
||||
escrow_fee_per_participant INTEGER,
|
||||
escrow_output_descriptor TEXT
|
||||
escrow_output_descriptor TEXT,
|
||||
payout_transaction_psbt_hex TEXT
|
||||
)", // escrow_psbt_is_confirmed will be set 1 once the escrow psbt is confirmed onchain
|
||||
)
|
||||
.execute(&db_pool)
|
||||
@ -890,4 +893,82 @@ impl CoordinatorDB {
|
||||
musig_pubkey_hex_taker,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn insert_keyspend_payout_psbt(
|
||||
&self,
|
||||
offer_id_hex: &str,
|
||||
payout_psbt_hex: &str,
|
||||
) -> Result<()> {
|
||||
sqlx::query("UPDATE taken_offers SET payout_transaction_psbt_hex = ? WHERE offer_id = ?")
|
||||
.bind(payout_psbt_hex)
|
||||
.bind(offer_id_hex)
|
||||
.execute(&*self.db_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_partitial_sig_and_fetch_if_both(
|
||||
&self,
|
||||
partitial_sig_hex: &str,
|
||||
offer_id_hex: &str,
|
||||
robohash_hex: &str,
|
||||
) -> Result<Option<(String, String, String)>> {
|
||||
// first check if the escrow psbt has already been submitted
|
||||
let is_maker = self
|
||||
.is_maker_in_taken_offers(offer_id_hex, robohash_hex)
|
||||
.await?;
|
||||
|
||||
let is_already_there = match is_maker {
|
||||
true => {
|
||||
let status = sqlx::query(
|
||||
"SELECT musig_partitial_sig_maker FROM taken_offers WHERE offer_id = ?",
|
||||
)
|
||||
.bind(offer_id_hex)
|
||||
.fetch_one(&*self.db_pool)
|
||||
.await?;
|
||||
status
|
||||
.get::<Option<String>, _>("musig_partitial_sig_maker")
|
||||
.is_some()
|
||||
}
|
||||
false => {
|
||||
let status = sqlx::query(
|
||||
"SELECT musig_partitial_sig_taker FROM taken_offers WHERE offer_id = ?",
|
||||
)
|
||||
.bind(offer_id_hex)
|
||||
.fetch_one(&*self.db_pool)
|
||||
.await?;
|
||||
status
|
||||
.get::<Option<String>, _>("musig_partitial_sig_taker")
|
||||
.is_some()
|
||||
}
|
||||
};
|
||||
|
||||
if is_already_there {
|
||||
return Err(anyhow!("Partial sig already submitted"));
|
||||
} else {
|
||||
let query = if is_maker {
|
||||
"UPDATE taken_offers SET musig_partitial_sig_maker = ? WHERE offer_id = ?"
|
||||
} else {
|
||||
"UPDATE taken_offers SET musig_partitial_sig_taker = ? WHERE offer_id = ?"
|
||||
};
|
||||
sqlx::query(query)
|
||||
.bind(partitial_sig_hex)
|
||||
.bind(offer_id_hex)
|
||||
.execute(&*self.db_pool)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let row = sqlx::query(
|
||||
"SELECT musig_partitial_sig_maker, musig_partitial_sig_taker, payout_transaction_psbt_hex FROM taken_offers WHERE offer_id = ?",
|
||||
).bind(offer_id_hex).fetch_one(&*self.db_pool).await?;
|
||||
|
||||
let maker_sig: Option<String> = row.try_get("musig_partitial_sig_maker")?;
|
||||
let taker_sig: Option<String> = row.try_get("musig_partitial_sig_taker")?;
|
||||
let payout_tx_hex: String = row.try_get("payout_transaction_psbt_hex")?;
|
||||
if let (Some(maker), Some(taker)) = (maker_sig, taker_sig) {
|
||||
Ok(Some((maker, taker, payout_tx_hex)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,10 @@ fn get_tx_fees_abs_sat(blockchain_backend: &RpcBlockchain) -> Result<(u64, u64)>
|
||||
Ok((tx_fee_abs, tx_fee_abs / 2))
|
||||
}
|
||||
|
||||
pub fn aggregate_partitial_signatures() -> anyhow::Result<String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
|
||||
fn get_escrow_utxo(
|
||||
&self,
|
||||
|
@ -22,6 +22,7 @@ use bdk::{
|
||||
database::MemoryDatabase,
|
||||
wallet::AddressInfo,
|
||||
};
|
||||
use reqwest::header::ACCEPT_LANGUAGE;
|
||||
use std::{str::FromStr, thread, time::Duration};
|
||||
|
||||
pub fn run_maker(maker_config: &TraderSettings) -> Result<()> {
|
||||
@ -52,10 +53,15 @@ pub fn run_maker(maker_config: &TraderSettings) -> Result<()> {
|
||||
info!("Waiting for other party to confirm the trade.");
|
||||
let (payout_keyspend_psbt, agg_pub_nonce, agg_pubk_ctx) =
|
||||
IsOfferReadyRequest::poll_payout(maker_config, &offer)?;
|
||||
|
||||
debug!("Payout PSBT received: {}", &payout_keyspend_psbt);
|
||||
let signed_payout_psbt = wallet
|
||||
.validate_payout_psbt(&payout_keyspend_psbt)?
|
||||
.sign_keyspend_payout_psbt(payout_keyspend_psbt, agg_pubk_ctx, agg_pub_nonce, local_musig_state: &offer.used_musig_config)?;
|
||||
.sign_keyspend_payout_psbt(
|
||||
payout_keyspend_psbt,
|
||||
agg_pubk_ctx,
|
||||
agg_pub_nonce,
|
||||
offer.used_musig_config,
|
||||
)?;
|
||||
// submit signed payout psbt back to coordinator
|
||||
panic!("Payout to be implemented!");
|
||||
} else {
|
||||
@ -86,7 +92,18 @@ pub fn run_taker(taker_config: &TraderSettings) -> Result<()> {
|
||||
TradeObligationsSatisfied::submit(&accepted_offer.offer_id_hex, taker_config)?;
|
||||
debug!("Waiting for other party to confirm the trade.");
|
||||
// pull for other parties confirmation, then receive the transaction to create MuSig signature for (keyspend) to payout address
|
||||
let payout_keyspend_psbt = IsOfferReadyRequest::poll_payout(taker_config, &accepted_offer)?;
|
||||
let (payout_keyspend_psbt, agg_pub_nonce, agg_pubk_ctx) =
|
||||
IsOfferReadyRequest::poll_payout(taker_config, &accepted_offer)?;
|
||||
|
||||
debug!("Received payout psbt: {}", &payout_keyspend_psbt);
|
||||
let signed_payout_psbt = wallet
|
||||
.validate_payout_psbt(&payout_keyspend_psbt)?
|
||||
.sign_keyspend_payout_psbt(
|
||||
payout_keyspend_psbt,
|
||||
agg_pubk_ctx,
|
||||
agg_pub_nonce,
|
||||
accepted_offer.used_musig_config,
|
||||
)?;
|
||||
// here we need to handle if the other party is not cooperating
|
||||
} else {
|
||||
error!("Trade failed.");
|
||||
|
@ -218,10 +218,9 @@ impl TradingWallet {
|
||||
validated_payout_psbt: PartiallySignedTransaction,
|
||||
key_agg_context: KeyAggContext,
|
||||
agg_pub_nonce: AggNonce,
|
||||
local_musig_state: &MuSigData,
|
||||
local_musig_state: MuSigData,
|
||||
) -> Result<String> {
|
||||
let payout_tx = validated_payout_psbt.extract_tx();
|
||||
let mut sig_hash_cache = SighashCache::new(payout_tx);
|
||||
let mut sig_hash_cache = SighashCache::new(validated_payout_psbt.unsigned_tx.clone());
|
||||
|
||||
let utxo = validated_payout_psbt
|
||||
.iter_funding_utxos()
|
||||
@ -230,10 +229,10 @@ impl TradingWallet {
|
||||
.clone();
|
||||
|
||||
// get the msg (sighash) to sign with the musig key
|
||||
let keyspend_sig_hash_msg = sig_hash_cache
|
||||
let binding = sig_hash_cache
|
||||
.taproot_key_spend_signature_hash(0, &Prevouts::All(&[utxo]), TapSighashType::All)
|
||||
.context("Failed to create keyspend sighash")?
|
||||
.as_byte_array();
|
||||
.context("Failed to create keyspend sighash")?;
|
||||
let keyspend_sig_hash_msg = binding.as_byte_array();
|
||||
|
||||
let secret_nonce = local_musig_state.nonce.get_sec_for_signing()?;
|
||||
let seckey = local_musig_state.secret_key;
|
||||
|
3
todos.md
3
todos.md
@ -1,8 +1,9 @@
|
||||
Thinks to improve when implementing the production ready library/coordinator:
|
||||
* secure user authentification scheme for calls / unique trade ids
|
||||
* make api more generic (smaller) / maybe use websockets
|
||||
* review escrow output descriptor, maybe make it smaller(less specific cases, more generic)?
|
||||
* maybe hard code descriptor instead of compiling it from pieces?
|
||||
* review for security flaws (error handling, logic bugs)
|
||||
* review for security flaws (error handling, logic bugs, crypto bugs)
|
||||
* maybe switch wallet completely to core rpc instead of bdk wallet + core rpc
|
||||
* api rate limiting (e.g. backoff) ?
|
||||
* build trader toolkit to get funds out of escrow if coordinator dissapears
|
||||
|
Reference in New Issue
Block a user