mirror of
https://github.com/floor-licker/polyfill-rs.git
synced 2026-08-05 08:47:45 +00:00
feat(clob): add batch order posting support
This commit is contained in:
+103
@@ -1032,12 +1032,68 @@ impl ClobClient {
|
||||
Ok(response.json::<Value>().await?)
|
||||
}
|
||||
|
||||
/// Post multiple orders to the exchange in a single request
|
||||
pub async fn post_orders(
|
||||
&self,
|
||||
orders: Vec<SignedOrderRequest>,
|
||||
order_type: OrderType,
|
||||
) -> Result<Value> {
|
||||
if orders.is_empty() {
|
||||
return Err(PolyfillError::validation("orders cannot be empty"));
|
||||
}
|
||||
|
||||
let signer = self
|
||||
.signer
|
||||
.as_ref()
|
||||
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
||||
let api_creds = self
|
||||
.api_creds
|
||||
.as_ref()
|
||||
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
||||
|
||||
let body: Vec<PostOrder> = orders
|
||||
.into_iter()
|
||||
.map(|order| PostOrder::new(order, api_creds.api_key.clone(), order_type))
|
||||
.collect();
|
||||
|
||||
let headers = create_l2_headers(signer, api_creds, "POST", "/orders", Some(&body))?;
|
||||
let req = self.create_request_with_headers(Method::POST, "/orders", headers.into_iter());
|
||||
|
||||
let response = req.json(&body).send().await?;
|
||||
if !response.status().is_success() {
|
||||
let status = response.status().as_u16();
|
||||
let body = response.text().await.unwrap_or_default();
|
||||
let message = if body.is_empty() {
|
||||
"Failed to post orders".to_string()
|
||||
} else {
|
||||
format!("Failed to post orders: {}", body)
|
||||
};
|
||||
return Err(PolyfillError::api(status, message));
|
||||
}
|
||||
|
||||
Ok(response.json::<Value>().await?)
|
||||
}
|
||||
|
||||
/// Create and post an order in one call
|
||||
pub async fn create_and_post_order(&self, order_args: &OrderArgs) -> Result<Value> {
|
||||
let order = self.create_order(order_args, None, None, None).await?;
|
||||
self.post_order(order, OrderType::GTC).await
|
||||
}
|
||||
|
||||
/// Create and post multiple orders in one call
|
||||
pub async fn create_and_post_orders(&self, order_args: &[OrderArgs]) -> Result<Value> {
|
||||
if order_args.is_empty() {
|
||||
return Err(PolyfillError::validation("order_args cannot be empty"));
|
||||
}
|
||||
|
||||
let mut orders = Vec::with_capacity(order_args.len());
|
||||
for args in order_args {
|
||||
orders.push(self.create_order(args, None, None, None).await?);
|
||||
}
|
||||
|
||||
self.post_orders(orders, OrderType::GTC).await
|
||||
}
|
||||
|
||||
/// Cancel an order
|
||||
pub async fn cancel(&self, order_id: &str) -> Result<Value> {
|
||||
let signer = self
|
||||
@@ -2874,6 +2930,53 @@ mod tests {
|
||||
assert_eq!(timestamp, 1234567890);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_post_orders_batch_success() {
|
||||
let mut server = Server::new_async().await;
|
||||
let mock = server
|
||||
.mock("POST", "/orders")
|
||||
.with_status(200)
|
||||
.with_header("content-type", "application/json")
|
||||
.with_body(r#"{"success":true,"orderIDs":["a","b"]}"#)
|
||||
.create_async()
|
||||
.await;
|
||||
|
||||
let client = create_test_client_with_l2_auth(&server.url());
|
||||
let signed_order = crate::types::SignedOrderRequest {
|
||||
salt: 1,
|
||||
maker: "0x0000000000000000000000000000000000000000".to_string(),
|
||||
signer: "0x0000000000000000000000000000000000000000".to_string(),
|
||||
taker: "0x0000000000000000000000000000000000000000".to_string(),
|
||||
token_id: "123".to_string(),
|
||||
maker_amount: "100".to_string(),
|
||||
taker_amount: "50".to_string(),
|
||||
expiration: "0".to_string(),
|
||||
nonce: "0".to_string(),
|
||||
fee_rate_bps: "0".to_string(),
|
||||
side: "BUY".to_string(),
|
||||
signature_type: 0,
|
||||
signature: "0xdeadbeef".to_string(),
|
||||
};
|
||||
|
||||
let result = client
|
||||
.post_orders(
|
||||
vec![signed_order.clone(), signed_order],
|
||||
crate::types::OrderType::GTC,
|
||||
)
|
||||
.await;
|
||||
|
||||
mock.assert_async().await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap()["success"], true);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_post_orders_batch_empty_validation() {
|
||||
let client = create_test_client_with_l2_auth("https://test.example.com");
|
||||
let result = client.post_orders(Vec::new(), crate::types::OrderType::GTC).await;
|
||||
assert!(matches!(result, Err(PolyfillError::Validation { .. })));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_create_or_derive_api_key() {
|
||||
let mut server = Server::new_async().await;
|
||||
|
||||
Reference in New Issue
Block a user