complete more api endpoints

This commit is contained in:
f321x
2024-07-19 17:25:15 +02:00
parent ff556bdc4f
commit 5a59ba63b0
3 changed files with 99 additions and 17 deletions

View File

@ -160,7 +160,7 @@ async fn request_offer_status_maker(
Json(payload): Json<OfferTakenRequest>,
) -> Result<Response, AppError> {
let offer = database
.fetch_taken_offer_maker(&payload.order_id_hex, &payload.robohash_hex)
.fetch_taken_offer_maker(&payload.offer_id_hex, &payload.robohash_hex)
.await?;
match offer {
Some(offer) => Ok(Json(OfferTakenResponse {
@ -196,13 +196,13 @@ async fn poll_escrow_confirmation(
Json(payload): Json<OfferTakenRequest>,
) -> Result<Response, AppError> {
if !database
.is_valid_robohash_in_table(&payload.robohash_hex, &payload.order_id_hex)
.is_valid_robohash_in_table(&payload.robohash_hex, &payload.offer_id_hex)
.await?
{
return Ok(StatusCode::NOT_FOUND.into_response());
}
if database
.fetch_escrow_tx_confirmation_status(&payload.order_id_hex)
.fetch_escrow_tx_confirmation_status(&payload.offer_id_hex)
.await?
{
return Ok(StatusCode::OK.into_response());
@ -213,20 +213,19 @@ async fn poll_escrow_confirmation(
async fn submit_obligation_confirmation(
Extension(database): Extension<Arc<CoordinatorDB>>,
Extension(wallet): Extension<Arc<CoordinatorWallet<sled::Tree>>>,
Json(payload): Json<OfferTakenRequest>,
) -> Result<Response, AppError> {
// sanity check if offer is in table and if the escrow tx is confirmed
if !database
.is_valid_robohash_in_table(&payload.robohash_hex, &payload.order_id_hex)
.is_valid_robohash_in_table(&payload.robohash_hex, &payload.offer_id_hex)
.await? || !database
.fetch_escrow_tx_confirmation_status(&payload.order_id_hex)
.fetch_escrow_tx_confirmation_status(&payload.offer_id_hex)
.await?
{
return Ok(StatusCode::NOT_FOUND.into_response());
}
database
.set_trader_happy_field(&payload.order_id_hex, &payload.robohash_hex, true)
.set_trader_happy_field(&payload.offer_id_hex, &payload.robohash_hex, true)
.await?;
Ok(StatusCode::OK.into_response())
}
@ -271,15 +270,44 @@ async fn poll_final_payout(
{
return Ok(StatusCode::NOT_FOUND.into_response());
}
// check if both traders are happy
// assemble payout psbt and return to them for signing
let trader_happiness = database
.fetch_trader_happiness(&payload.offer_id_hex)
.await?;
if trader_happiness.maker_happy.is_some_and(|x| x == true)
&& trader_happiness.taker_happy.is_some_and(|x| x == true)
{
panic!("Implement wallet.assemble_keyspend_payout_psbt()");
// let payout_keyspend_psbt_hex = wallet
// .assemble_keyspend_payout_psbt(&payload.offer_id_hex, &payload.robohash_hex)
// .await
// .context("Error assembling payout PSBT")?;
// return Ok(String::from(payout_keyspend_psbt_hex).into_response());
} else if (trader_happiness.maker_happy.is_none() || trader_happiness.taker_happy.is_none())
&& !trader_happiness.escrow_ongoing
{
return Ok(StatusCode::ACCEPTED.into_response());
}
// if one of them is not happy
// open escrow cli on coordinator to decide who will win (chat/dispute is out of scope for this demo)
// once decided who will win assemble the correct payout psbt and return it to the according trader
// the other trader gets a error code/ end of trade code
panic!("implement")
// escrow winner has to be set true with a cli input of the coordinator. This could be an api
// endpoint for the admin UI frontend in the future
if let Some(escrow_winner) = database.fetch_escrow_result(&payload.offer_id_hex).await? {
if escrow_winner == payload.robohash_hex {
panic!("Implement wallet.assemble_script_payout_psbt()");
// let script_payout_psbt_hex = wallet
// .assemble_script_payout_psbt(&payload.offer_id_hex, &payload.robohash_hex, is_maker_bool)
// .await
// .context("Error assembling payout PSBT")?;
// return Ok(String::from(payout_keyspend_psbt_hex).into_response());
} else {
return Ok(StatusCode::GONE.into_response()); // this will be returned to the losing trader
}
} else {
return Ok(StatusCode::PROCESSING.into_response()); // this will be returned if the coordinator hasn't decided yet
}
}
async fn test_api() -> &'static str {

View File

@ -40,6 +40,12 @@ struct AwaitingTakerOffer {
musig_pubkey_hex_maker: String,
}
pub struct TraderHappiness {
pub maker_happy: Option<bool>,
pub taker_happy: Option<bool>,
pub escrow_ongoing: bool,
}
fn bool_to_sql_int(flag: bool) -> Option<i64> {
if flag {
Some(1)
@ -126,6 +132,8 @@ impl CoordinatorDB {
escrow_psbt_is_confirmed INTEGER,
maker_happy INTEGER,
taker_happy INTEGER,
escrow_ongoing INTEGER NOT NULL,
escrow_winner_robohash TEXT
)", // escrow_psbt_is_confirmed will be set 1 once the escrow psbt is confirmed onchain
)
.execute(&db_pool)
@ -351,8 +359,8 @@ impl CoordinatorDB {
"INSERT OR REPLACE INTO taken_offers (offer_id, robohash_maker, robohash_taker, is_buy_order, amount_sat,
bond_ratio, offer_duration_ts, bond_address_maker, bond_address_taker, bond_amount_sat, bond_tx_hex_maker,
bond_tx_hex_taker, payout_address_maker, payout_address_taker, musig_pub_nonce_hex_maker, musig_pubkey_hex_maker,
musig_pub_nonce_hex_taker, musig_pubkey_hex_taker, escrow_psbt_hex_maker, escrow_psbt_hex_taker, escrow_psbt_txid, escrow_psbt_is_confirmed)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
musig_pub_nonce_hex_taker, musig_pubkey_hex_taker, escrow_psbt_hex_maker, escrow_psbt_hex_taker, escrow_psbt_txid, escrow_psbt_is_confirmed, escrow_ongoing)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
)
.bind(public_offer.offer_id)
.bind(public_offer.robohash_maker)
@ -376,6 +384,7 @@ impl CoordinatorDB {
.bind(trade_contract_psbt_taker.clone())
.bind(trade_tx_txid)
.bind(0)
.bind(0)
.execute(&*self.db_pool)
.await?;
@ -613,6 +622,44 @@ impl CoordinatorDB {
.execute(&*self.db_pool)
.await?;
if !is_happy {
sqlx::query("UPDATE taken_offers SET escrow_ongoing = 1 WHERE offer_id = ?")
.bind(offer_id)
.execute(&*self.db_pool)
.await?;
}
Ok(())
}
pub async fn fetch_trader_happiness(&self, offer_id: &String) -> Result<TraderHappiness> {
let row = sqlx::query(
"SELECT maker_happy, taker_happy, escrow_ongoing FROM taken_offers WHERE offer_id = ?",
)
.bind(offer_id)
.fetch_one(&*self.db_pool)
.await?;
let maker_happy: Option<i64> = row.try_get::<Option<i64>, _>("maker_happy")?;
let taker_happy: Option<i64> = row.try_get::<Option<i64>, _>("taker_happy")?;
let escrow_ongoing: i64 = row.try_get::<i64, _>("escrow_ongoing")?;
Ok(TraderHappiness {
maker_happy: maker_happy.map(|v| v != 0),
taker_happy: taker_happy.map(|v| v != 0),
escrow_ongoing: escrow_ongoing != 0,
})
}
pub async fn fetch_escrow_result(&self, offer_id: &String) -> Result<Option<String>> {
let row = sqlx::query("SELECT escrow_winner_robohash FROM taken_offers WHERE offer_id = ?")
.bind(offer_id)
.fetch_one(&*self.db_pool)
.await?;
let winner_robohash: Option<String> =
row.try_get::<Option<String>, _>("escrow_winner_robohash")?;
Ok(winner_robohash)
}
}

View File

@ -15,7 +15,7 @@ use bdk::{
wallet::AddressInfo,
};
use serde::{Deserialize, Serialize};
use std::{str::FromStr, thread::sleep, time::Duration};
use std::{f32::consts::E, str::FromStr, thread::sleep, time::Duration};
impl BondRequirementResponse {
fn _format_request(trader_setup: &TraderSettings) -> OrderRequest {
@ -257,13 +257,20 @@ impl IsOfferReadyRequest {
.send()?;
if res.status() == 200 {
// good case, psbt is returned
debug!("Payout psbt received. Signing...");
break;
} else if res.status() == 204 {
} else if res.status() == 202 {
// still waiting, retry
continue;
} else if res.status() == 201 {
} else if res.status() == 102 {
// other party initiated escrow
return Ok(None);
debug!("Other party initiated escrow. Waiting for coordinator to finalize.");
continue;
} else if res.status() != 410 {
return Err(anyhow!(
"We lost the escrow, your bond is gone: {}",
res.status()
));
} else {
// unintended response
return Err(anyhow!(