mirror of
https://github.com/RoboSats/taptrade-core.git
synced 2025-08-03 16:40:08 +00:00
add sanity checks to coordinator endpoint
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
./taptrade-cli-demo/target
|
./taptrade-cli-demo/target
|
||||||
taptrade-cli-demo/target
|
taptrade-cli-demo/target
|
||||||
taptrade-cli-demo/coordinator/target
|
taptrade-cli-demo/coordinator/target
|
||||||
taptrade-cli-demo/trader/target
|
taptrade-cli-demo/coordinator/dbs/*
|
||||||
|
taptrade-cli-demo/trader/target
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
pub mod api;
|
pub mod api;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use self::api::*;
|
use self::api::*;
|
||||||
|
use self::utils::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use axum::{
|
use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -19,6 +21,9 @@ async fn receive_order(
|
|||||||
Extension(wallet): Extension<CoordinatorWallet>,
|
Extension(wallet): Extension<CoordinatorWallet>,
|
||||||
Json(order): Json<OrderRequest>,
|
Json(order): Json<OrderRequest>,
|
||||||
) -> Result<Json<BondRequirementResponse>, AppError> {
|
) -> Result<Json<BondRequirementResponse>, AppError> {
|
||||||
|
if order.sanity_check().is_err() {
|
||||||
|
return Err(AppError(anyhow!("Invalid order request")));
|
||||||
|
}
|
||||||
let bond_requirements = BondRequirementResponse {
|
let bond_requirements = BondRequirementResponse {
|
||||||
bond_address: wallet.get_new_address().await?,
|
bond_address: wallet.get_new_address().await?,
|
||||||
locking_amount_sat: order.amount_satoshi * order.bond_ratio as u64 / 100,
|
locking_amount_sat: order.amount_satoshi * order.bond_ratio as u64 / 100,
|
||||||
@ -31,20 +36,37 @@ async fn receive_order(
|
|||||||
Ok(Json(bond_requirements))
|
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(
|
async fn submit_maker_bond(
|
||||||
Extension(database): Extension<CoordinatorDB>,
|
Extension(database): Extension<CoordinatorDB>,
|
||||||
Extension(wallet): Extension<CoordinatorWallet>,
|
Extension(wallet): Extension<CoordinatorWallet>,
|
||||||
Json(payload): Json<BondSubmissionRequest>,
|
Json(payload): Json<BondSubmissionRequest>,
|
||||||
) -> Result<Json<OrderActivatedResponse>, AppError> {
|
) -> 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
|
// For now, we'll just return a dummy success response
|
||||||
let response = OrderActivatedResponse {
|
let response = OrderActivatedResponse {
|
||||||
bond_locked_until_timestamp: 0 as u128,
|
bond_locked_until_timestamp: 0 as u128,
|
||||||
order_id_hex: "Bond submitted successfully".to_string(),
|
order_id_hex: "Bond submitted successfully".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create the JSON response
|
// Create the JSON response
|
||||||
Json(response)
|
Ok(Json(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn api_server(database: CoordinatorDB, wallet: CoordinatorWallet) -> Result<()> {
|
pub async fn api_server(database: CoordinatorDB, wallet: CoordinatorWallet) -> Result<()> {
|
||||||
|
31
taptrade-cli-demo/coordinator/src/communication/utils.rs
Normal file
31
taptrade-cli-demo/coordinator/src/communication/utils.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@ pub fn verify_and_respond(
|
|||||||
wallet: &Wallet<MemoryDatabase>,
|
wallet: &Wallet<MemoryDatabase>,
|
||||||
) -> Result<OrderActivatedResponse> {
|
) -> Result<OrderActivatedResponse> {
|
||||||
// Deserialize the signed bond hex
|
// 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)
|
// Verify the transaction (this example assumes you've implemented your own verification logic)
|
||||||
let is_valid = verify_psbt(&tx, &wallet, &bond_submission)?;
|
let is_valid = verify_psbt(&tx, &wallet, &bond_submission)?;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use sqlx::{sqlite::SqlitePoolOptions, Pool, Sqlite};
|
use sqlx::{sqlite::SqlitePoolOptions, Pool, Row, Sqlite};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CoordinatorDB {
|
pub struct CoordinatorDB {
|
||||||
@ -70,4 +70,18 @@ impl CoordinatorDB {
|
|||||||
|
|
||||||
Ok(())
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
mod communication;
|
mod communication;
|
||||||
// mod coordinator;
|
mod coordinator;
|
||||||
mod database;
|
mod database;
|
||||||
mod wallet;
|
mod wallet;
|
||||||
|
|
||||||
@ -7,6 +7,7 @@ use anyhow::{anyhow, Result};
|
|||||||
use communication::{api::*, api_server};
|
use communication::{api::*, api_server};
|
||||||
use database::CoordinatorDB;
|
use database::CoordinatorDB;
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use std::{env, sync::Arc};
|
use std::{env, sync::Arc};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use wallet::CoordinatorWallet;
|
use wallet::CoordinatorWallet;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use bdk::{
|
use bdk::{
|
||||||
bitcoin::{self, bip32::ExtendedPrivKey},
|
bitcoin::{self, bip32::ExtendedPrivKey, consensus::encode::deserialize, Transaction},
|
||||||
blockchain::ElectrumBlockchain,
|
blockchain::ElectrumBlockchain,
|
||||||
electrum_client::Client,
|
electrum_client::Client,
|
||||||
sled::{self, Tree},
|
sled::{self, Tree},
|
||||||
@ -46,4 +46,11 @@ impl CoordinatorWallet {
|
|||||||
let address = wallet.get_address(bdk::wallet::AddressIndex::New)?;
|
let address = wallet.get_address(bdk::wallet::AddressIndex::New)?;
|
||||||
Ok(address.address.to_string())
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user