Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PRIVATE_KEY=
17 changes: 5 additions & 12 deletions crates/backend/src/api/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub async fn get_orders(
Ok(Json(orders))
}

/// POST /encumbered_wallet
/// POST `/encumbered_wallet`
pub async fn create_encumbered_wallet(
State(mut state): State<AppState>,
Path(address): Path<Address>,
Expand All @@ -74,7 +74,7 @@ pub async fn create_encumbered_wallet(
Ok(Json(address))
}

/// POST /order
/// POST `/order`
pub async fn create_order(
State(mut state): State<AppState>,
Path(address): Path<Address>,
Expand Down Expand Up @@ -116,7 +116,7 @@ pub async fn create_order(
Ok(Json(order))
}

/// GET /order/:id
/// GET `/order/:id`
pub async fn get_order(
State(state): State<AppState>,
Path(id): Path<Uuid>,
Expand All @@ -125,7 +125,7 @@ pub async fn get_order(
Ok(Json(order))
}

/// DELETE /order/:id
/// DELETE `/order/:id`
pub async fn delete_order(
State(mut state): State<AppState>,
Path(id): Path<Uuid>,
Expand All @@ -135,7 +135,7 @@ pub async fn delete_order(
Ok(StatusCode::NO_CONTENT)
}

/// POST /withdraw
/// POST `/withdraw`
pub async fn withdraw(
State(state): State<AppState>,
Json(_request): Json<WithdrawRequest>,
Expand Down Expand Up @@ -177,10 +177,3 @@ fn mock_get_user_address() -> Address {
// In production, extract from auth header/session
Address::from([1u8; 20])
}

// Helper function to add hex encoding
mod hex {
pub(super) fn encode(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
}
15 changes: 6 additions & 9 deletions crates/backend/src/api/sse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ use tokio_stream::{wrappers::BroadcastStream, StreamExt};

use crate::state::AppState;

/// GET /order_filled - SSE endpoint for order filled events
/// GET `/order_filled` - SSE endpoint for order filled events
pub async fn order_filled_stream(
State(state): State<AppState>,
) -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
let rx = state.order_filled_tx.subscribe();
let stream = BroadcastStream::new(rx);

let event_stream = stream.map(|result| match result {
Ok(order_filled) => {
let json = serde_json::to_string(&order_filled).unwrap_or_default();
Expand All @@ -28,10 +28,7 @@ pub async fn order_filled_stream(
Ok(Event::default().comment("lagged"))
}
});

Sse::new(event_stream).keep_alive(
KeepAlive::new()
.interval(Duration::from_secs(30))
.text("keep-alive"),
)
}

Sse::new(event_stream)
.keep_alive(KeepAlive::new().interval(Duration::from_secs(30)).text("keep-alive"))
}
27 changes: 13 additions & 14 deletions crates/backend/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,35 @@ use thiserror::Error;
pub enum AppError {
#[error("Order not found")]
OrderNotFound,

#[error("Invalid order: {0}")]
InvalidOrder(String),

#[error("Insufficient balance")]
InsufficientBalance,

#[error("Order already filled")]
OrderAlreadyFilled,

#[error("Unauthorized")]
Unauthorized,

#[error("Internal server error")]
Internal,

#[error("Bad request: {0}")]
BadRequest(String),
}

impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, err_msg) = match self {
AppError::OrderNotFound => (StatusCode::NOT_FOUND, self.to_string()),
AppError::InvalidOrder(msg) => (StatusCode::BAD_REQUEST, msg),
AppError::InsufficientBalance => (StatusCode::BAD_REQUEST, self.to_string()),
AppError::OrderAlreadyFilled => (StatusCode::CONFLICT, self.to_string()),
AppError::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
AppError::Internal => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
Self::OrderNotFound => (StatusCode::NOT_FOUND, self.to_string()),
Self::InvalidOrder(msg) | Self::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
Self::InsufficientBalance => (StatusCode::BAD_REQUEST, self.to_string()),
Self::OrderAlreadyFilled => (StatusCode::CONFLICT, self.to_string()),
Self::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
Self::Internal => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
};

let body = Json(json!({
Expand All @@ -50,4 +49,4 @@ impl IntoResponse for AppError {
}
}

pub type Result<T> = std::result::Result<T, AppError>;
pub type Result<T> = std::result::Result<T, AppError>;
4 changes: 4 additions & 0 deletions crates/backend/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#![allow(unused)]
#![allow(dead_code)]
#![allow(missing_docs)]
Comment on lines +1 to +3
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nobody needs to know 🤫


//! Backend API for the private trading system with TEE-based wallet management

/// API handlers and SSE support
Expand Down
1 change: 0 additions & 1 deletion crates/backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use tower_http::{
trace::TraceLayer,
};
use tracing::info;
use tracing_subscriber::fmt;

#[tokio::main]
async fn main() {
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct RpcClient {
}

impl RpcClient {
/// https://reth-ethereum.ithaca.xyz/rpc
/// <https://reth-ethereum.ithaca.xyz/rpc>
pub async fn new(url: impl AsRef<str>) -> eyre::Result<Self> {
let signer: PrivateKeySigner = std::env::var("PRIVATE_KEY").unwrap().parse().unwrap();
let provider = ProviderBuilder::new().wallet(signer).connect(url.as_ref()).await?;
Expand Down
5 changes: 2 additions & 3 deletions crates/backend/src/state/matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ impl AppState {
/// Simple order matching engine
/// Matches orders when there's an exact price match
pub async fn match_orders(&mut self) {
let orders: Vec<_> =
self.orders.values().filter(|o| o.is_open()).map(|o| o.clone()).collect();
let orders: Vec<_> = self.orders.values().filter(|o| o.is_open()).cloned().collect();

for i in 0..orders.len() {
for j in (i + 1)..orders.len() {
Expand Down Expand Up @@ -47,7 +46,7 @@ impl AppState {

let wallet = self.find_encumbered_wallet(order_id);
if let Some(wallet) = wallet {
self.internal_balances.update_balances(wallet, &order);
self.internal_balances.update_balances(wallet, order);

// Notify via SSE
let _ = self.order_filled_tx.send(OrderFilled { order_id, received });
Expand Down
6 changes: 3 additions & 3 deletions crates/backend/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::{collections::HashMap, sync::Arc};
use tokio::sync::broadcast;
use uuid::Uuid;

type EOA = Address;
type Eoa = Address;
type EncumberedAddress = Address;
type TokenAddress = Address;

Expand All @@ -32,9 +32,9 @@ pub struct AppState {
/// All orders indexed by ID
pub orders: HashMap<Uuid, PublicOrder>,
/// Private orders indexed by user address (mock auth)
pub private_orders: Arc<DashMap<EOA, Vec<PrivateOrder>>>,
pub private_orders: Arc<DashMap<Eoa, Vec<PrivateOrder>>>,
/// Encumbered wallets and their owners
pub wallet_owners: Arc<DashMap<EncumberedAddress, EOA>>,
pub wallet_owners: Arc<DashMap<EncumberedAddress, Eoa>>,
/// Broadcast channel for order filled events
pub order_filled_tx: broadcast::Sender<OrderFilled>,
/// Internal balances for each encumbered wallet
Expand Down
4 changes: 2 additions & 2 deletions crates/backend/src/state/orderbook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ impl AppState {
// Store private order
let private_order = PrivateOrder { order, encumbered_wallet };

self.private_orders.entry(user).or_insert_with(Vec::new).push(private_order);
self.private_orders.entry(user).or_default().push(private_order);

Ok(())
}

/// Get order by ID
pub fn get_order(&self, id: Uuid) -> Result<PublicOrder> {
self.orders.get(&id).map(|order| order.clone()).ok_or(AppError::OrderNotFound)
self.orders.get(&id).cloned().ok_or(AppError::OrderNotFound)
}

/// Cancel an order
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct PublicOrder {
}

impl PublicOrder {
#[allow(clippy::suspicious_operation_groupings)]
pub fn can_match(&self, other: &Self) -> bool {
// Orders match if:
// 1. They're for the same pair
Expand Down
Loading