223 lines
5.9 KiB
Rust
223 lines
5.9 KiB
Rust
use axum::{
|
|
routing::{get, post},
|
|
Router,
|
|
Json,
|
|
extract::{Path, State},
|
|
};
|
|
use validator::Validate;
|
|
use std::sync::Arc;
|
|
use chrono::Utc;
|
|
use serde::Serialize;
|
|
|
|
use crate::blockchain::NacClient;
|
|
use crate::error::ApiError;
|
|
use crate::models::{CreateOrderRequest, OrderResponse, MarketDataResponse};
|
|
|
|
#[derive(Clone)]
|
|
pub struct ExchangeState {
|
|
pub client: Arc<NacClient>,
|
|
}
|
|
|
|
pub fn routes(client: Arc<NacClient>) -> Router {
|
|
let state = ExchangeState { client };
|
|
|
|
Router::new()
|
|
.route("/assets", get(get_assets))
|
|
.route("/orders", post(create_order))
|
|
.route("/orders/:order_id", get(get_order))
|
|
.route("/market/:asset", get(get_market_data))
|
|
.route("/orderbook/:asset", get(get_orderbook))
|
|
.route("/trades", get(get_trades))
|
|
.with_state(state)
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct Asset {
|
|
id: String,
|
|
name: String,
|
|
symbol: String,
|
|
price: String,
|
|
volume_24h: String,
|
|
change_24h: String,
|
|
}
|
|
|
|
async fn get_assets(
|
|
State(_state): State<ExchangeState>,
|
|
) -> Result<Json<Vec<Asset>>, ApiError> {
|
|
// TODO: 从RWA交易所合约获取资产列表
|
|
Ok(Json(vec![
|
|
Asset {
|
|
id: "asset1".to_string(),
|
|
name: "房产Token A".to_string(),
|
|
symbol: "RWA-A".to_string(),
|
|
price: "1000.00".to_string(),
|
|
volume_24h: "50000.00".to_string(),
|
|
change_24h: "+2.5%".to_string(),
|
|
},
|
|
Asset {
|
|
id: "asset2".to_string(),
|
|
name: "艺术品Token B".to_string(),
|
|
symbol: "RWA-B".to_string(),
|
|
price: "500.00".to_string(),
|
|
volume_24h: "30000.00".to_string(),
|
|
change_24h: "-1.2%".to_string(),
|
|
},
|
|
]))
|
|
}
|
|
|
|
async fn create_order(
|
|
State(_state): State<ExchangeState>,
|
|
Json(req): Json<CreateOrderRequest>,
|
|
) -> Result<Json<OrderResponse>, ApiError> {
|
|
// 验证请求参数
|
|
req.validate()
|
|
.map_err(|e: validator::ValidationErrors| ApiError::ValidationError(e.to_string()))?;
|
|
|
|
// 生成订单ID
|
|
let order_id = uuid::Uuid::new_v4().to_string();
|
|
|
|
// TODO: 实际应该调用RWA交易所合约创建订单
|
|
Ok(Json(OrderResponse {
|
|
order_id,
|
|
asset: req.asset,
|
|
amount: req.amount,
|
|
price: req.price,
|
|
order_type: req.order_type,
|
|
status: "pending".to_string(),
|
|
created_at: Utc::now().timestamp(),
|
|
}))
|
|
}
|
|
|
|
async fn get_order(
|
|
State(_state): State<ExchangeState>,
|
|
Path(order_id): Path<String>,
|
|
) -> Result<Json<OrderResponse>, ApiError> {
|
|
// 验证订单ID
|
|
if order_id.is_empty() {
|
|
return Err(ApiError::ValidationError("Invalid order ID".to_string()));
|
|
}
|
|
|
|
// TODO: 从区块链或数据库获取订单详情
|
|
Ok(Json(OrderResponse {
|
|
order_id,
|
|
asset: "XTZH".to_string(),
|
|
amount: "100.00".to_string(),
|
|
price: "1.00".to_string(),
|
|
order_type: "buy".to_string(),
|
|
status: "filled".to_string(),
|
|
created_at: Utc::now().timestamp(),
|
|
}))
|
|
}
|
|
|
|
async fn get_market_data(
|
|
State(_state): State<ExchangeState>,
|
|
Path(asset): Path<String>,
|
|
) -> Result<Json<MarketDataResponse>, ApiError> {
|
|
// 验证资产符号
|
|
if asset.is_empty() {
|
|
return Err(ApiError::ValidationError("Invalid asset symbol".to_string()));
|
|
}
|
|
|
|
// TODO: 从区块链或价格预言机获取市场数据
|
|
Ok(Json(MarketDataResponse {
|
|
asset,
|
|
price: "1.00".to_string(),
|
|
volume_24h: "1000000.00".to_string(),
|
|
change_24h: "+2.5%".to_string(),
|
|
high_24h: "1.05".to_string(),
|
|
low_24h: "0.95".to_string(),
|
|
}))
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct OrderbookResponse {
|
|
asset: String,
|
|
bids: Vec<OrderLevel>,
|
|
asks: Vec<OrderLevel>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct OrderLevel {
|
|
price: String,
|
|
amount: String,
|
|
total: String,
|
|
}
|
|
|
|
async fn get_orderbook(
|
|
State(_state): State<ExchangeState>,
|
|
Path(asset): Path<String>,
|
|
) -> Result<Json<OrderbookResponse>, ApiError> {
|
|
// 验证资产符号
|
|
if asset.is_empty() {
|
|
return Err(ApiError::ValidationError("Invalid asset symbol".to_string()));
|
|
}
|
|
|
|
// TODO: 从RWA交易所合约获取订单簿
|
|
Ok(Json(OrderbookResponse {
|
|
asset,
|
|
bids: vec![
|
|
OrderLevel {
|
|
price: "0.99".to_string(),
|
|
amount: "1000.00".to_string(),
|
|
total: "990.00".to_string(),
|
|
},
|
|
OrderLevel {
|
|
price: "0.98".to_string(),
|
|
amount: "2000.00".to_string(),
|
|
total: "1960.00".to_string(),
|
|
},
|
|
],
|
|
asks: vec![
|
|
OrderLevel {
|
|
price: "1.01".to_string(),
|
|
amount: "1500.00".to_string(),
|
|
total: "1515.00".to_string(),
|
|
},
|
|
OrderLevel {
|
|
price: "1.02".to_string(),
|
|
amount: "2500.00".to_string(),
|
|
total: "2550.00".to_string(),
|
|
},
|
|
],
|
|
}))
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct Trade {
|
|
id: String,
|
|
asset: String,
|
|
price: String,
|
|
amount: String,
|
|
timestamp: i64,
|
|
trade_type: String,
|
|
}
|
|
|
|
async fn get_trades(
|
|
State(_state): State<ExchangeState>,
|
|
) -> Result<Json<Vec<Trade>>, ApiError> {
|
|
// TODO: 从RWA交易所合约获取最近交易
|
|
Ok(Json(vec![
|
|
Trade {
|
|
id: uuid::Uuid::new_v4().to_string(),
|
|
asset: "RWA-A".to_string(),
|
|
price: "1000.00".to_string(),
|
|
amount: "5.00".to_string(),
|
|
timestamp: Utc::now().timestamp(),
|
|
trade_type: "buy".to_string(),
|
|
},
|
|
]))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_exchange_state_creation() {
|
|
let client = Arc::new(NacClient::new("http://localhost:8545".to_string()));
|
|
let state = ExchangeState { client };
|
|
// 验证state创建成功
|
|
assert!(Arc::strong_count(&state.client) >= 1);
|
|
}
|
|
}
|