mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-07-25 20:23:18 +00:00
complete more api endpoints
This commit is contained in:
@ -160,7 +160,7 @@ async fn request_offer_status_maker(
|
|||||||
Json(payload): Json<OfferTakenRequest>,
|
Json(payload): Json<OfferTakenRequest>,
|
||||||
) -> Result<Response, AppError> {
|
) -> Result<Response, AppError> {
|
||||||
let offer = database
|
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?;
|
.await?;
|
||||||
match offer {
|
match offer {
|
||||||
Some(offer) => Ok(Json(OfferTakenResponse {
|
Some(offer) => Ok(Json(OfferTakenResponse {
|
||||||
@ -196,13 +196,13 @@ async fn poll_escrow_confirmation(
|
|||||||
Json(payload): Json<OfferTakenRequest>,
|
Json(payload): Json<OfferTakenRequest>,
|
||||||
) -> Result<Response, AppError> {
|
) -> Result<Response, AppError> {
|
||||||
if !database
|
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?
|
.await?
|
||||||
{
|
{
|
||||||
return Ok(StatusCode::NOT_FOUND.into_response());
|
return Ok(StatusCode::NOT_FOUND.into_response());
|
||||||
}
|
}
|
||||||
if database
|
if database
|
||||||
.fetch_escrow_tx_confirmation_status(&payload.order_id_hex)
|
.fetch_escrow_tx_confirmation_status(&payload.offer_id_hex)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
return Ok(StatusCode::OK.into_response());
|
return Ok(StatusCode::OK.into_response());
|
||||||
@ -213,20 +213,19 @@ async fn poll_escrow_confirmation(
|
|||||||
|
|
||||||
async fn submit_obligation_confirmation(
|
async fn submit_obligation_confirmation(
|
||||||
Extension(database): Extension<Arc<CoordinatorDB>>,
|
Extension(database): Extension<Arc<CoordinatorDB>>,
|
||||||
Extension(wallet): Extension<Arc<CoordinatorWallet<sled::Tree>>>,
|
|
||||||
Json(payload): Json<OfferTakenRequest>,
|
Json(payload): Json<OfferTakenRequest>,
|
||||||
) -> Result<Response, AppError> {
|
) -> Result<Response, AppError> {
|
||||||
// sanity check if offer is in table and if the escrow tx is confirmed
|
// sanity check if offer is in table and if the escrow tx is confirmed
|
||||||
if !database
|
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
|
.await? || !database
|
||||||
.fetch_escrow_tx_confirmation_status(&payload.order_id_hex)
|
.fetch_escrow_tx_confirmation_status(&payload.offer_id_hex)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
return Ok(StatusCode::NOT_FOUND.into_response());
|
return Ok(StatusCode::NOT_FOUND.into_response());
|
||||||
}
|
}
|
||||||
database
|
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?;
|
.await?;
|
||||||
Ok(StatusCode::OK.into_response())
|
Ok(StatusCode::OK.into_response())
|
||||||
}
|
}
|
||||||
@ -271,15 +270,44 @@ async fn poll_final_payout(
|
|||||||
{
|
{
|
||||||
return Ok(StatusCode::NOT_FOUND.into_response());
|
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
|
// 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)
|
// 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
|
// 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
|
// the other trader gets a error code/ end of trade code
|
||||||
|
// escrow winner has to be set true with a cli input of the coordinator. This could be an api
|
||||||
panic!("implement")
|
// 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 {
|
async fn test_api() -> &'static str {
|
||||||
|
@ -40,6 +40,12 @@ struct AwaitingTakerOffer {
|
|||||||
musig_pubkey_hex_maker: String,
|
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> {
|
fn bool_to_sql_int(flag: bool) -> Option<i64> {
|
||||||
if flag {
|
if flag {
|
||||||
Some(1)
|
Some(1)
|
||||||
@ -126,6 +132,8 @@ impl CoordinatorDB {
|
|||||||
escrow_psbt_is_confirmed INTEGER,
|
escrow_psbt_is_confirmed INTEGER,
|
||||||
maker_happy INTEGER,
|
maker_happy INTEGER,
|
||||||
taker_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
|
)", // escrow_psbt_is_confirmed will be set 1 once the escrow psbt is confirmed onchain
|
||||||
)
|
)
|
||||||
.execute(&db_pool)
|
.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,
|
"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_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,
|
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)
|
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
)
|
)
|
||||||
.bind(public_offer.offer_id)
|
.bind(public_offer.offer_id)
|
||||||
.bind(public_offer.robohash_maker)
|
.bind(public_offer.robohash_maker)
|
||||||
@ -376,6 +384,7 @@ impl CoordinatorDB {
|
|||||||
.bind(trade_contract_psbt_taker.clone())
|
.bind(trade_contract_psbt_taker.clone())
|
||||||
.bind(trade_tx_txid)
|
.bind(trade_tx_txid)
|
||||||
.bind(0)
|
.bind(0)
|
||||||
|
.bind(0)
|
||||||
.execute(&*self.db_pool)
|
.execute(&*self.db_pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -613,6 +622,44 @@ impl CoordinatorDB {
|
|||||||
.execute(&*self.db_pool)
|
.execute(&*self.db_pool)
|
||||||
.await?;
|
.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(())
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use bdk::{
|
|||||||
wallet::AddressInfo,
|
wallet::AddressInfo,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
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 {
|
impl BondRequirementResponse {
|
||||||
fn _format_request(trader_setup: &TraderSettings) -> OrderRequest {
|
fn _format_request(trader_setup: &TraderSettings) -> OrderRequest {
|
||||||
@ -257,13 +257,20 @@ impl IsOfferReadyRequest {
|
|||||||
.send()?;
|
.send()?;
|
||||||
if res.status() == 200 {
|
if res.status() == 200 {
|
||||||
// good case, psbt is returned
|
// good case, psbt is returned
|
||||||
|
debug!("Payout psbt received. Signing...");
|
||||||
break;
|
break;
|
||||||
} else if res.status() == 204 {
|
} else if res.status() == 202 {
|
||||||
// still waiting, retry
|
// still waiting, retry
|
||||||
continue;
|
continue;
|
||||||
} else if res.status() == 201 {
|
} else if res.status() == 102 {
|
||||||
// other party initiated escrow
|
// 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 {
|
} else {
|
||||||
// unintended response
|
// unintended response
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
|
Reference in New Issue
Block a user