add sanity checks to coordinator endpoint

This commit is contained in:
f321x
2024-06-26 14:26:19 +00:00
parent 49550dac66
commit 6dacb2433d
7 changed files with 84 additions and 8 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
./taptrade-cli-demo/target
taptrade-cli-demo/target
taptrade-cli-demo/coordinator/target
taptrade-cli-demo/coordinator/dbs/*
taptrade-cli-demo/trader/target

View File

@ -1,6 +1,8 @@
pub mod api;
mod utils;
use self::api::*;
use self::utils::*;
use super::*;
use axum::{
http::StatusCode,
@ -19,6 +21,9 @@ async fn receive_order(
Extension(wallet): Extension<CoordinatorWallet>,
Json(order): Json<OrderRequest>,
) -> Result<Json<BondRequirementResponse>, AppError> {
if order.sanity_check().is_err() {
return Err(AppError(anyhow!("Invalid order request")));
}
let bond_requirements = BondRequirementResponse {
bond_address: wallet.get_new_address().await?,
locking_amount_sat: order.amount_satoshi * order.bond_ratio as u64 / 100,
@ -31,20 +36,37 @@ async fn receive_order(
Ok(Json(bond_requirements))
}
// BondSubmissionRequest {
// pub robohash_hex: String,
// pub signed_bond_hex: String, // signed bond transaction, hex encoded
// pub payout_address: String,
// pub musig_pub_nonce_hex: String,
// pub musig_pubkey_hex: String,
async fn submit_maker_bond(
Extension(database): Extension<CoordinatorDB>,
Extension(wallet): Extension<CoordinatorWallet>,
Json(payload): Json<BondSubmissionRequest>,
) -> Result<Json<OrderActivatedResponse>, AppError> {
// Process the payload
let bond_requirements = database.fetch_maker_request(&payload.robohash_hex).await?;
// validate bond (check amounts, valid inputs, correct addresses, valid signature, feerate)
wallet
.validate_bond_tx_hex(&payload.signed_bond_hex)
.await?;
// insert bond into sql database
// begin monitoring bond
// move trade to orderbook
// For now, we'll just return a dummy success response
let response = OrderActivatedResponse {
bond_locked_until_timestamp: 0 as u128,
order_id_hex: "Bond submitted successfully".to_string(),
};
// Create the JSON response
Json(response)
Ok(Json(response))
}
pub async fn api_server(database: CoordinatorDB, wallet: CoordinatorWallet) -> Result<()> {

View File

@ -0,0 +1,31 @@
use anyhow::Context;
use super::*;
impl OrderRequest {
pub fn sanity_check(&self) -> Result<()> {
// Get the current time
let now = SystemTime::now();
// Convert the current time to a UNIX timestamp
let unix_timestamp = now
.duration_since(UNIX_EPOCH)
.context("Time went backwards")?
.as_secs();
if self.amount_satoshi < 10000 {
return Err(anyhow!("Amount too low"));
}
if self.amount_satoshi > 20000000 {
return Err(anyhow!("Amount too high"));
}
if self.bond_ratio < 2 || self.bond_ratio > 50 {
return Err(anyhow!("Bond ratio out of bounds"));
}
if self.offer_duration_ts < unix_timestamp + 10800 {
return Err(anyhow!("Offer duration too short"));
}
if self.offer_duration_ts > unix_timestamp + 604800 {
return Err(anyhow!("Offer duration too long"));
}
Ok(())
}
}

View File

@ -16,7 +16,7 @@ pub fn verify_and_respond(
wallet: &Wallet<MemoryDatabase>,
) -> Result<OrderActivatedResponse> {
// Deserialize the signed bond hex
let tx: Transaction = deserialize(hex::decode(bond_submission.signed_bond_hex)?.as_slice())?;
let tx: Transaction = deserialize(&hex::decode(&bond_submission.signed_bond_hex)?)?;
// Verify the transaction (this example assumes you've implemented your own verification logic)
let is_valid = verify_psbt(&tx, &wallet, &bond_submission)?;

View File

@ -1,7 +1,7 @@
use anyhow::Context;
use super::*;
use sqlx::{sqlite::SqlitePoolOptions, Pool, Sqlite};
use sqlx::{sqlite::SqlitePoolOptions, Pool, Row, Sqlite};
#[derive(Clone, Debug)]
pub struct CoordinatorDB {
@ -70,4 +70,18 @@ impl CoordinatorDB {
Ok(())
}
pub async fn fetch_maker_request(&self, robohash: &String) -> Result<BondRequirementResponse> {
let maker_request = sqlx::query(
"SELECT bond_address, bond_amount_sat FROM maker_requests WHERE robohash = ?",
)
.bind(hex::decode(robohash)?)
.fetch_one(&*self.db_pool)
.await?;
Ok(BondRequirementResponse {
bond_address: maker_request.try_get("bond_address")?,
locking_amount_sat: maker_request.try_get::<i64, _>("bond_amount_sat")? as u64,
})
}
}

View File

@ -1,5 +1,5 @@
mod communication;
// mod coordinator;
mod coordinator;
mod database;
mod wallet;
@ -7,6 +7,7 @@ use anyhow::{anyhow, Result};
use communication::{api::*, api_server};
use database::CoordinatorDB;
use dotenv::dotenv;
use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, sync::Arc};
use tokio::sync::Mutex;
use wallet::CoordinatorWallet;

View File

@ -1,7 +1,7 @@
use super::*;
use anyhow::Context;
use bdk::{
bitcoin::{self, bip32::ExtendedPrivKey},
bitcoin::{self, bip32::ExtendedPrivKey, consensus::encode::deserialize, Transaction},
blockchain::ElectrumBlockchain,
electrum_client::Client,
sled::{self, Tree},
@ -46,4 +46,11 @@ impl CoordinatorWallet {
let address = wallet.get_address(bdk::wallet::AddressIndex::New)?;
Ok(address.address.to_string())
}
// validate bond (check amounts, valid inputs, correct addresses, valid signature, feerate)
pub async fn validate_bond_tx_hex(&self, bond: &String) -> Result<bool> {
let tx: Transaction = deserialize(&hex::decode(bond)?)?;
Ok(true)
}
}